tizen 2.3.1 release tizen_2.3.1 submit/tizen_2.3.1/20150915.080726 tizen_2.3.1_release
authorjk7744.park <jk7744.park@samsung.com>
Tue, 8 Sep 2015 13:21:46 +0000 (22:21 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Tue, 8 Sep 2015 13:21:46 +0000 (22:21 +0900)
752 files changed:
.gitignore [new file with mode: 0644]
Android.mk [new file with mode: 0644]
CONTRIBUTIONS
COPYING
README
build_nsis.sh [deleted file]
build_release
configurations/tizen.config
configurations/tizen_hostapd.config
debian/changelog [deleted file]
debian/compat [deleted file]
debian/control [deleted file]
debian/rules [deleted file]
debian/wpasupplicant.install.in [deleted file]
doc/.gitignore [new file with mode: 0644]
doc/Makefile
doc/code_structure.doxygen
doc/ctrl_iface.doxygen
doc/dbus.doxygen
doc/doxygen.conf
doc/mainpage.doxygen
doc/p2p.doxygen [new file with mode: 0644]
doc/p2p_arch.dot [new file with mode: 0644]
doc/p2p_arch2.dot [new file with mode: 0644]
doc/p2p_sm.dot [new file with mode: 0644]
eap_example/.gitignore [new file with mode: 0644]
eap_example/README
eap_example/eap_example.c
eap_example/eap_example_peer.c
eap_example/eap_example_server.c
files/wpa_supp.sh [new file with mode: 0755]
hostapd/Android.mk
hostapd/ChangeLog
hostapd/Makefile
hostapd/README
hostapd/README-WPS
hostapd/android.config [new file with mode: 0644]
hostapd/config_file.c
hostapd/config_file.h
hostapd/ctrl_iface.c
hostapd/ctrl_iface.h
hostapd/defconfig
hostapd/dump_state.c
hostapd/dump_state.h
hostapd/eap_register.c
hostapd/eap_register.h
hostapd/hlr_auc_gw.c
hostapd/hlr_auc_gw.txt [new file with mode: 0644]
hostapd/hostapd.conf
hostapd/hostapd.eap_user
hostapd/hostapd.eap_user_sqlite [new file with mode: 0644]
hostapd/hostapd_cli.c
hostapd/main.c
hostapd/nt_password_hash.c
hostapd/wps-ap-nfc.py [new file with mode: 0755]
mac80211_hwsim/tools/hwsim_test.c
packaging/wpa_supplicant.changes [deleted file]
packaging/wpa_supplicant.manifest
packaging/wpa_supplicant.spec [deleted file]
packaging/wpasupplicant.spec [new file with mode: 0644]
patches/openssl-0.9.8x-tls-extensions.patch [new file with mode: 0644]
radius_example/.gitignore [new file with mode: 0644]
radius_example/README
radius_example/radius_example.c
src/ap/accounting.c
src/ap/accounting.h
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/ap_list.c
src/ap/ap_list.h
src/ap/ap_mlme.c
src/ap/ap_mlme.h
src/ap/authsrv.c
src/ap/authsrv.h
src/ap/beacon.c
src/ap/beacon.h
src/ap/ctrl_iface_ap.c
src/ap/ctrl_iface_ap.h
src/ap/drv_callbacks.c
src/ap/eap_user_db.c [new file with mode: 0644]
src/ap/gas_serv.c [new file with mode: 0644]
src/ap/gas_serv.h [new file with mode: 0644]
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/hs20.c [new file with mode: 0644]
src/ap/hs20.h [new file with mode: 0644]
src/ap/hw_features.c
src/ap/iapp.c
src/ap/iapp.h
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_auth.c
src/ap/ieee802_11_auth.h
src/ap/ieee802_11_ht.c
src/ap/ieee802_11_shared.c
src/ap/ieee802_11_vht.c [new file with mode: 0644]
src/ap/ieee802_1x.c
src/ap/ieee802_1x.h
src/ap/p2p_hostapd.c
src/ap/p2p_hostapd.h
src/ap/peerkey_auth.c
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/preauth_auth.c
src/ap/preauth_auth.h
src/ap/sta_info.c
src/ap/sta_info.h
src/ap/tkip_countermeasures.c
src/ap/tkip_countermeasures.h
src/ap/utils.c
src/ap/vlan_init.c
src/ap/vlan_util.c [new file with mode: 0644]
src/ap/vlan_util.h [new file with mode: 0644]
src/ap/wnm_ap.c [new file with mode: 0644]
src/ap/wnm_ap.h [new file with mode: 0644]
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_glue.h
src/ap/wpa_auth_i.h
src/ap/wpa_auth_ie.c
src/ap/wpa_auth_ie.h
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/defs.h
src/common/eapol_common.h
src/common/gas.c
src/common/gas.h
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
src/common/privsep_commands.h
src/common/sae.c [new file with mode: 0644]
src/common/sae.h [new file with mode: 0644]
src/common/version.h
src/common/wpa_common.c
src/common/wpa_common.h
src/common/wpa_ctrl.c
src/common/wpa_ctrl.h
src/crypto/.gitignore [new file with mode: 0644]
src/crypto/Makefile
src/crypto/aes-cbc.c
src/crypto/aes-ccm.c [new file with mode: 0644]
src/crypto/aes-ctr.c
src/crypto/aes-eax.c
src/crypto/aes-encblock.c
src/crypto/aes-gcm.c [new file with mode: 0644]
src/crypto/aes-internal-dec.c
src/crypto/aes-internal-enc.c
src/crypto/aes-internal.c
src/crypto/aes-omac1.c
src/crypto/aes-unwrap.c
src/crypto/aes-wrap.c
src/crypto/aes.h
src/crypto/aes_i.h
src/crypto/aes_wrap.h
src/crypto/crypto.h
src/crypto/crypto_cryptoapi.c
src/crypto/crypto_gnutls.c
src/crypto/crypto_internal-cipher.c
src/crypto/crypto_internal-modexp.c
src/crypto/crypto_internal-rsa.c
src/crypto/crypto_internal.c
src/crypto/crypto_libtomcrypt.c
src/crypto/crypto_none.c
src/crypto/crypto_nss.c
src/crypto/crypto_openssl.c
src/crypto/des-internal.c
src/crypto/des_i.h
src/crypto/dh_group5.c
src/crypto/dh_group5.h
src/crypto/dh_groups.c
src/crypto/dh_groups.h
src/crypto/fips_prf_cryptoapi.c
src/crypto/fips_prf_gnutls.c
src/crypto/fips_prf_internal.c
src/crypto/fips_prf_nss.c
src/crypto/fips_prf_openssl.c
src/crypto/md4-internal.c
src/crypto/md5-internal.c
src/crypto/md5-non-fips.c [deleted file]
src/crypto/md5.c
src/crypto/md5.h
src/crypto/md5_i.h
src/crypto/milenage.c
src/crypto/milenage.h
src/crypto/ms_funcs.c
src/crypto/ms_funcs.h
src/crypto/random.c
src/crypto/random.h
src/crypto/rc4.c
src/crypto/sha1-internal.c
src/crypto/sha1-pbkdf2.c
src/crypto/sha1-prf.c [new file with mode: 0644]
src/crypto/sha1-tlsprf.c
src/crypto/sha1-tprf.c
src/crypto/sha1.c
src/crypto/sha1.h
src/crypto/sha1_i.h
src/crypto/sha256-internal.c
src/crypto/sha256-prf.c [new file with mode: 0644]
src/crypto/sha256-tlsprf.c
src/crypto/sha256.c
src/crypto/sha256.h
src/crypto/sha256_i.h
src/crypto/tls.h
src/crypto/tls_gnutls.c
src/crypto/tls_internal.c
src/crypto/tls_none.c
src/crypto/tls_nss.c
src/crypto/tls_openssl.c
src/crypto/tls_schannel.c
src/drivers/.gitignore [new file with mode: 0644]
src/drivers/driver.h
src/drivers/driver_atheros.c
src/drivers/driver_bsd.c
src/drivers/driver_common.c
src/drivers/driver_hostap.c
src/drivers/driver_hostap.h
src/drivers/driver_madwifi.c
src/drivers/driver_ndis.c
src/drivers/driver_ndis.h
src/drivers/driver_ndis_.c
src/drivers/driver_nl80211.c
src/drivers/driver_none.c
src/drivers/driver_openbsd.c [new file with mode: 0644]
src/drivers/driver_privsep.c
src/drivers/driver_roboswitch.c
src/drivers/driver_test.c
src/drivers/driver_wext.c
src/drivers/driver_wext.h
src/drivers/driver_wired.c
src/drivers/drivers.c
src/drivers/drivers.mak
src/drivers/drivers.mk
src/drivers/linux_ioctl.c
src/drivers/linux_ioctl.h
src/drivers/linux_wext.h
src/drivers/ndis_events.c
src/drivers/netlink.c
src/drivers/netlink.h
src/drivers/nl80211_copy.h
src/drivers/priv_netlink.h
src/drivers/rfkill.c
src/drivers/rfkill.h
src/eap_common/chap.c
src/eap_common/chap.h
src/eap_common/eap_common.c
src/eap_common/eap_common.h
src/eap_common/eap_defs.h
src/eap_common/eap_fast_common.c
src/eap_common/eap_fast_common.h
src/eap_common/eap_gpsk_common.c
src/eap_common/eap_gpsk_common.h
src/eap_common/eap_ikev2_common.c
src/eap_common/eap_ikev2_common.h
src/eap_common/eap_pax_common.c
src/eap_common/eap_pax_common.h
src/eap_common/eap_peap_common.c
src/eap_common/eap_peap_common.h
src/eap_common/eap_psk_common.c
src/eap_common/eap_psk_common.h
src/eap_common/eap_pwd_common.c
src/eap_common/eap_pwd_common.h
src/eap_common/eap_sake_common.c
src/eap_common/eap_sake_common.h
src/eap_common/eap_sim_common.c
src/eap_common/eap_sim_common.h
src/eap_common/eap_tlv_common.h
src/eap_common/eap_ttls.h
src/eap_common/eap_wsc_common.c
src/eap_common/eap_wsc_common.h
src/eap_common/ikev2_common.c
src/eap_common/ikev2_common.h
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_aka.c
src/eap_peer/eap_config.h
src/eap_peer/eap_fast.c
src/eap_peer/eap_fast_pac.c
src/eap_peer/eap_fast_pac.h
src/eap_peer/eap_gpsk.c
src/eap_peer/eap_gtc.c
src/eap_peer/eap_i.h
src/eap_peer/eap_ikev2.c
src/eap_peer/eap_leap.c
src/eap_peer/eap_md5.c
src/eap_peer/eap_methods.c
src/eap_peer/eap_methods.h
src/eap_peer/eap_mschapv2.c
src/eap_peer/eap_otp.c
src/eap_peer/eap_pax.c
src/eap_peer/eap_peap.c
src/eap_peer/eap_proxy.h [new file with mode: 0644]
src/eap_peer/eap_proxy_dummy.c [new file with mode: 0644]
src/eap_peer/eap_psk.c
src/eap_peer/eap_pwd.c
src/eap_peer/eap_sake.c
src/eap_peer/eap_sim.c
src/eap_peer/eap_tls.c
src/eap_peer/eap_tls_common.c
src/eap_peer/eap_tls_common.h
src/eap_peer/eap_tnc.c
src/eap_peer/eap_ttls.c
src/eap_peer/eap_vendor_test.c
src/eap_peer/eap_wsc.c
src/eap_peer/ikev2.c
src/eap_peer/ikev2.h
src/eap_peer/mschapv2.c
src/eap_peer/mschapv2.h
src/eap_peer/tncc.c
src/eap_peer/tncc.h
src/eap_server/eap.h
src/eap_server/eap_i.h
src/eap_server/eap_methods.h
src/eap_server/eap_server.c
src/eap_server/eap_server_aka.c
src/eap_server/eap_server_fast.c
src/eap_server/eap_server_gpsk.c
src/eap_server/eap_server_gtc.c
src/eap_server/eap_server_identity.c
src/eap_server/eap_server_ikev2.c
src/eap_server/eap_server_md5.c
src/eap_server/eap_server_methods.c
src/eap_server/eap_server_mschapv2.c
src/eap_server/eap_server_pax.c
src/eap_server/eap_server_peap.c
src/eap_server/eap_server_psk.c
src/eap_server/eap_server_pwd.c
src/eap_server/eap_server_sake.c
src/eap_server/eap_server_sim.c
src/eap_server/eap_server_tls.c
src/eap_server/eap_server_tls_common.c
src/eap_server/eap_server_tnc.c
src/eap_server/eap_server_ttls.c
src/eap_server/eap_server_vendor_test.c
src/eap_server/eap_server_wsc.c
src/eap_server/eap_sim_db.c
src/eap_server/eap_sim_db.h
src/eap_server/eap_tls_common.h
src/eap_server/ikev2.c
src/eap_server/ikev2.h
src/eap_server/tncs.c
src/eap_server/tncs.h
src/eapol_auth/eapol_auth_dump.c
src/eapol_auth/eapol_auth_sm.c
src/eapol_auth/eapol_auth_sm.h
src/eapol_auth/eapol_auth_sm_i.h
src/eapol_supp/eapol_supp_sm.c
src/eapol_supp/eapol_supp_sm.h
src/l2_packet/l2_packet.h
src/l2_packet/l2_packet_freebsd.c
src/l2_packet/l2_packet_linux.c
src/l2_packet/l2_packet_ndis.c
src/l2_packet/l2_packet_none.c
src/l2_packet/l2_packet_pcap.c
src/l2_packet/l2_packet_privsep.c
src/l2_packet/l2_packet_winpcap.c
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_build.c
src/p2p/p2p_dev_disc.c
src/p2p/p2p_go_neg.c
src/p2p/p2p_group.c
src/p2p/p2p_i.h
src/p2p/p2p_invitation.c
src/p2p/p2p_parse.c
src/p2p/p2p_pd.c
src/p2p/p2p_sd.c
src/p2p/p2p_utils.c
src/radius/.gitignore [new file with mode: 0644]
src/radius/radius.c
src/radius/radius.h
src/radius/radius_client.c
src/radius/radius_client.h
src/radius/radius_das.c [new file with mode: 0644]
src/radius/radius_das.h [new file with mode: 0644]
src/radius/radius_server.c
src/radius/radius_server.h
src/rsn_supp/peerkey.c
src/rsn_supp/peerkey.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/preauth.c
src/rsn_supp/preauth.h
src/rsn_supp/tdls.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_ft.c
src/rsn_supp/wpa_i.h
src/rsn_supp/wpa_ie.c
src/rsn_supp/wpa_ie.h
src/tls/.gitignore [new file with mode: 0644]
src/tls/asn1.c
src/tls/asn1.h
src/tls/bignum.c
src/tls/bignum.h
src/tls/libtommath.c
src/tls/pkcs1.c
src/tls/pkcs1.h
src/tls/pkcs5.c
src/tls/pkcs5.h
src/tls/pkcs8.c
src/tls/pkcs8.h
src/tls/rsa.c
src/tls/rsa.h
src/tls/tlsv1_client.c
src/tls/tlsv1_client.h
src/tls/tlsv1_client_i.h
src/tls/tlsv1_client_read.c
src/tls/tlsv1_client_write.c
src/tls/tlsv1_common.c
src/tls/tlsv1_common.h
src/tls/tlsv1_cred.c
src/tls/tlsv1_cred.h
src/tls/tlsv1_record.c
src/tls/tlsv1_record.h
src/tls/tlsv1_server.c
src/tls/tlsv1_server.h
src/tls/tlsv1_server_i.h
src/tls/tlsv1_server_read.c
src/tls/tlsv1_server_write.c
src/tls/x509v3.c
src/tls/x509v3.h
src/utils/.gitignore [new file with mode: 0644]
src/utils/Makefile
src/utils/base64.c
src/utils/base64.h
src/utils/bitfield.c [new file with mode: 0644]
src/utils/bitfield.h [new file with mode: 0644]
src/utils/build_config.h
src/utils/common.c
src/utils/common.h
src/utils/edit.c
src/utils/edit.h
src/utils/edit_readline.c
src/utils/edit_simple.c
src/utils/eloop.c
src/utils/eloop.h
src/utils/eloop_none.c
src/utils/eloop_win.c
src/utils/ext_password.c [new file with mode: 0644]
src/utils/ext_password.h [new file with mode: 0644]
src/utils/ext_password_i.h [new file with mode: 0644]
src/utils/ext_password_test.c [new file with mode: 0644]
src/utils/includes.h
src/utils/ip_addr.c
src/utils/ip_addr.h
src/utils/list.h
src/utils/os.h
src/utils/os_internal.c
src/utils/os_none.c
src/utils/os_unix.c
src/utils/os_win32.c
src/utils/pcsc_funcs.c
src/utils/pcsc_funcs.h
src/utils/state_machine.h
src/utils/trace.c
src/utils/trace.h
src/utils/uuid.c
src/utils/uuid.h
src/utils/wpa_debug.c
src/utils/wpa_debug.h
src/utils/wpabuf.c
src/utils/wpabuf.h
src/wps/http_client.c
src/wps/http_client.h
src/wps/http_server.c
src/wps/http_server.h
src/wps/httpread.c
src/wps/httpread.h
src/wps/ndef.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_attr_build.c
src/wps/wps_attr_parse.c
src/wps/wps_attr_parse.h [new file with mode: 0644]
src/wps/wps_attr_process.c
src/wps/wps_common.c
src/wps/wps_defs.h
src/wps/wps_dev_attr.c
src/wps/wps_dev_attr.h
src/wps/wps_enrollee.c
src/wps/wps_er.c
src/wps/wps_er.h
src/wps/wps_er_ssdp.c
src/wps/wps_i.h
src/wps/wps_nfc.c [deleted file]
src/wps/wps_nfc_pn531.c [deleted file]
src/wps/wps_registrar.c
src/wps/wps_ufd.c [deleted file]
src/wps/wps_upnp.c
src/wps/wps_upnp_ap.c
src/wps/wps_upnp_i.h
src/wps/wps_upnp_ssdp.c
src/wps/wps_upnp_web.c
src/wps/wps_validate.c
tests/.gitignore [new file with mode: 0644]
tests/Makefile
tests/hwsim/hostapd.py [new file with mode: 0644]
tests/hwsim/hwsim_utils.py [new file with mode: 0644]
tests/hwsim/p2p0.conf [new file with mode: 0644]
tests/hwsim/p2p1.conf [new file with mode: 0644]
tests/hwsim/p2p2.conf [new file with mode: 0644]
tests/hwsim/run-all.sh [new file with mode: 0755]
tests/hwsim/run-tests.py [new file with mode: 0755]
tests/hwsim/sta-dummy.conf [new file with mode: 0644]
tests/hwsim/start-p2p-concurrent.sh [new file with mode: 0755]
tests/hwsim/start.sh [new file with mode: 0755]
tests/hwsim/stop-wifi.sh [new file with mode: 0755]
tests/hwsim/test_ap_ft.py [new file with mode: 0644]
tests/hwsim/test_ap_hs20.py [new file with mode: 0644]
tests/hwsim/test_ap_pmf.py [new file with mode: 0644]
tests/hwsim/test_ap_roam.py [new file with mode: 0644]
tests/hwsim/test_ap_tdls.py [new file with mode: 0644]
tests/hwsim/test_ap_wps.py [new file with mode: 0644]
tests/hwsim/test_nfc_wps.py [new file with mode: 0644]
tests/hwsim/test_p2p_autogo.py [new file with mode: 0644]
tests/hwsim/test_p2p_discovery.py [new file with mode: 0644]
tests/hwsim/test_p2p_grpform.py [new file with mode: 0644]
tests/hwsim/wlantest.py [new file with mode: 0644]
tests/hwsim/wpasupplicant.py [new file with mode: 0644]
tests/test-aes.c
tests/test-asn1.c
tests/test-base64.c
tests/test-bitfield.c [new file with mode: 0644]
tests/test-https.c
tests/test-list.c
tests/test-md4.c
tests/test-md5.c
tests/test-ms_funcs.c
tests/test-printf.c [new file with mode: 0644]
tests/test-rc4.c
tests/test-sha1.c
tests/test-sha256.c
tests/test-x509.c
tests/test-x509v3.c
wlantest/Makefile
wlantest/bip.c [new file with mode: 0644]
wlantest/bss.c
wlantest/ccmp.c
wlantest/crc32.c
wlantest/ctrl.c
wlantest/gcmp.c [new file with mode: 0644]
wlantest/inject.c
wlantest/monitor.c
wlantest/process.c
wlantest/readpcap.c
wlantest/rx_data.c
wlantest/rx_eapol.c
wlantest/rx_ip.c
wlantest/rx_mgmt.c
wlantest/rx_tdls.c
wlantest/sta.c
wlantest/test_vectors.c [new file with mode: 0644]
wlantest/tkip.c
wlantest/wep.c
wlantest/wired.c
wlantest/wlantest.c
wlantest/wlantest.h
wlantest/wlantest_cli.c
wlantest/wlantest_ctrl.h
wlantest/writepcap.c
wpa_supplicant/.gitignore [new file with mode: 0644]
wpa_supplicant/Android.mk
wpa_supplicant/ChangeLog
wpa_supplicant/Makefile
wpa_supplicant/README
wpa_supplicant/README-HS20 [new file with mode: 0644]
wpa_supplicant/README-P2P
wpa_supplicant/README-WPS
wpa_supplicant/README-Windows.txt
wpa_supplicant/android.config [new file with mode: 0644]
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/autoscan.c [new file with mode: 0644]
wpa_supplicant/autoscan.h [new file with mode: 0644]
wpa_supplicant/autoscan_exponential.c [new file with mode: 0644]
wpa_supplicant/autoscan_periodic.c [new file with mode: 0644]
wpa_supplicant/bgscan.c
wpa_supplicant/bgscan.h
wpa_supplicant/bgscan_learn.c
wpa_supplicant/bgscan_simple.c
wpa_supplicant/blacklist.c
wpa_supplicant/blacklist.h
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/config_none.c
wpa_supplicant/config_ssid.h
wpa_supplicant/config_winreg.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/ctrl_iface.h
wpa_supplicant/ctrl_iface_named_pipe.c
wpa_supplicant/ctrl_iface_udp.c
wpa_supplicant/ctrl_iface_unix.c
wpa_supplicant/dbus/.gitignore [new file with mode: 0644]
wpa_supplicant/dbus/Makefile
wpa_supplicant/dbus/dbus-wpa_supplicant.conf
wpa_supplicant/dbus/dbus_common.c
wpa_supplicant/dbus/dbus_common.h
wpa_supplicant/dbus/dbus_common_i.h
wpa_supplicant/dbus/dbus_dict_helpers.c
wpa_supplicant/dbus/dbus_dict_helpers.h
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new.h
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/dbus/dbus_new_handlers.h
wpa_supplicant/dbus/dbus_new_handlers_p2p.c
wpa_supplicant/dbus/dbus_new_handlers_p2p.h
wpa_supplicant/dbus/dbus_new_handlers_wps.c
wpa_supplicant/dbus/dbus_new_helpers.c
wpa_supplicant/dbus/dbus_new_helpers.h
wpa_supplicant/dbus/dbus_new_introspect.c
wpa_supplicant/dbus/dbus_old.c
wpa_supplicant/dbus/dbus_old.h
wpa_supplicant/dbus/dbus_old_handlers.c
wpa_supplicant/dbus/dbus_old_handlers.h
wpa_supplicant/dbus/dbus_old_handlers_wps.c
wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
wpa_supplicant/defconfig
wpa_supplicant/doc/docbook/.gitignore [new file with mode: 0644]
wpa_supplicant/doc/docbook/wpa_background.sgml
wpa_supplicant/doc/docbook/wpa_cli.sgml
wpa_supplicant/doc/docbook/wpa_gui.sgml
wpa_supplicant/doc/docbook/wpa_passphrase.sgml
wpa_supplicant/doc/docbook/wpa_priv.sgml
wpa_supplicant/doc/docbook/wpa_supplicant.sgml
wpa_supplicant/driver_i.h
wpa_supplicant/eap_proxy_dummy.mk [new file with mode: 0644]
wpa_supplicant/eap_register.c
wpa_supplicant/eapol_test.c
wpa_supplicant/events.c
wpa_supplicant/examples/dbus-listen-preq.py [new file with mode: 0755]
wpa_supplicant/examples/p2p/p2p_connect.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_disconnect.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_find.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_flush.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_group_add.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_invite.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_listen.py [new file with mode: 0644]
wpa_supplicant/examples/p2p/p2p_stop_find.py [new file with mode: 0644]
wpa_supplicant/examples/wpas-dbus-new-signals.py
wpa_supplicant/examples/wps-nfc.py [new file with mode: 0755]
wpa_supplicant/gas_query.c
wpa_supplicant/gas_query.h
wpa_supplicant/hs20_supplicant.c [new file with mode: 0644]
wpa_supplicant/hs20_supplicant.h [new file with mode: 0644]
wpa_supplicant/ibss_rsn.c
wpa_supplicant/ibss_rsn.h
wpa_supplicant/interworking.c
wpa_supplicant/interworking.h
wpa_supplicant/main.c
wpa_supplicant/main_none.c
wpa_supplicant/main_symbian.cpp [deleted file]
wpa_supplicant/main_winmain.c
wpa_supplicant/main_winsvc.c
wpa_supplicant/nfc_pw_token.c [new file with mode: 0644]
wpa_supplicant/notify.c
wpa_supplicant/notify.h
wpa_supplicant/offchannel.c
wpa_supplicant/offchannel.h
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/preauth_test.c
wpa_supplicant/scan.c
wpa_supplicant/scan.h
wpa_supplicant/sme.c
wpa_supplicant/sme.h
wpa_supplicant/symbian/README.symbian [deleted file]
wpa_supplicant/symbian/bld.inf [deleted file]
wpa_supplicant/symbian/wpa_supplicant.mmp [deleted file]
wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in [moved from wpa_supplicant/systemd/wpa_supplicant-nl80211@.service.in with 85% similarity]
wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in [moved from wpa_supplicant/systemd/wpa_supplicant-wired@.service.in with 85% similarity]
wpa_supplicant/systemd/wpa_supplicant.service.arg.in [moved from wpa_supplicant/systemd/wpa_supplicant@.service.in with 86% similarity]
wpa_supplicant/systemd/wpa_supplicant.service.in
wpa_supplicant/tests/test_eap_sim_common.c
wpa_supplicant/tests/test_wpa.c
wpa_supplicant/utils/log2pcap.py [new file with mode: 0755]
wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
wpa_supplicant/wifi_display.c [new file with mode: 0644]
wpa_supplicant/wifi_display.h [new file with mode: 0644]
wpa_supplicant/win_if_list.c
wpa_supplicant/wnm_sta.c [new file with mode: 0644]
wpa_supplicant/wnm_sta.h [new file with mode: 0644]
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_gui-qt4/.gitignore [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/addinterface.cpp
wpa_supplicant/wpa_gui-qt4/addinterface.h
wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
wpa_supplicant/wpa_gui-qt4/eventhistory.h
wpa_supplicant/wpa_gui-qt4/lang/.gitignore [new file with mode: 0644]
wpa_supplicant/wpa_gui-qt4/main.cpp
wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
wpa_supplicant/wpa_gui-qt4/networkconfig.h
wpa_supplicant/wpa_gui-qt4/peers.cpp
wpa_supplicant/wpa_gui-qt4/peers.h
wpa_supplicant/wpa_gui-qt4/scanresults.cpp
wpa_supplicant/wpa_gui-qt4/scanresults.h
wpa_supplicant/wpa_gui-qt4/signalbar.cpp
wpa_supplicant/wpa_gui-qt4/signalbar.h
wpa_supplicant/wpa_gui-qt4/stringquery.cpp
wpa_supplicant/wpa_gui-qt4/stringquery.h
wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
wpa_supplicant/wpa_gui-qt4/userdatarequest.h
wpa_supplicant/wpa_gui-qt4/wpagui.cpp
wpa_supplicant/wpa_gui-qt4/wpagui.h
wpa_supplicant/wpa_gui-qt4/wpamsg.h
wpa_supplicant/wpa_passphrase.c
wpa_supplicant/wpa_priv.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant.nsi [deleted file]
wpa_supplicant/wpa_supplicant_conf.mk [new file with mode: 0644]
wpa_supplicant/wpa_supplicant_conf.sh [new file with mode: 0755]
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpa_supplicant_template.conf [new file with mode: 0644]
wpa_supplicant/wpas_glue.c
wpa_supplicant/wpas_glue.h
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h
wpadebug/AndroidManifest.xml [new file with mode: 0644]
wpadebug/README [new file with mode: 0644]
wpadebug/build.xml [new file with mode: 0644]
wpadebug/project.properties [new file with mode: 0644]
wpadebug/res/layout/cred_edit.xml [new file with mode: 0644]
wpadebug/res/layout/main.xml [new file with mode: 0644]
wpadebug/res/raw/shell_commands.txt [new file with mode: 0644]
wpadebug/res/raw/wpa_commands.txt [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/CommandListActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/MainActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WifiReceiver.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java [new file with mode: 0644]
wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java [new file with mode: 0644]
wpaspy/Makefile [new file with mode: 0644]
wpaspy/setup.py [new file with mode: 0644]
wpaspy/test.py [new file with mode: 0755]
wpaspy/wpaspy.c [new file with mode: 0644]
wpaspy/wpaspy.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c9f0507
--- /dev/null
@@ -0,0 +1,22 @@
+*.[oa]
+*~
+.project
+.cproject
+build-stamp
+debian/files
+debian/wpasupplicant-dbg.debhelper.log
+debian/wpasupplicant-dbg.substvars
+debian/wpasupplicant-dbg
+debian/wpasupplicant.debhelper.log
+debian/wpasupplicant.install
+debian/wpasupplicant.substvars
+debian/wpasupplicant
+wpa_supplicant/.config
+wpa_supplicant/wpa_cli
+wpa_supplicant/wpa_passphrase
+wpa_supplicant/wpa_supplicant
+hostapd/.config
+hostapd/hostapd
+hostapd/hostapd_cli
+src/drivers/build.wpa_supplicant
+src/drivers/build.hostapd
diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..c2cc68b
--- /dev/null
@@ -0,0 +1,3 @@
+ifeq ($(WPA_SUPPLICANT_VERSION),VER_2_1_DEVEL)
+    include $(call all-subdir-makefiles)
+endif
index 7670769..5ac7868 100644 (file)
@@ -13,17 +13,25 @@ The items (a) through (d) are identical to the Developer's Certificate
 of Origin 1.1. To enable cleaner licensing option to be provided in the
 future, an additional item (e) is included.
 
-In case of most files in hostap.git, "under the open source license
-indicated in the file" means that the contribution is licensed both
-under GPL v2 and modified BSD license (see below) and the choice between
-these licenses is given to anyone who redistributes or uses the
-software. As such, the contribution has to be licensed under both
-options to allow this choice.
+Until February 11, 2012, in case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed both under GPL v2 and modified BSD license (see below) and
+the choice between these licenses is given to anyone who redistributes
+or uses the software. As such, the contribution has to be licensed under
+both options to allow this choice.
+
+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 and the contributions are not required to be
+licensed until GPL v2. In case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed under the modified BSD license (see below).
+
 
 The additional item (e) is used to collect explicit approval to license
 the contribution with only the modified BSD license (see below), i.e.,
-without the GPL v2 option. This is done to allow simpler licensing terms
-to be used in the future. It should be noted that the modified BSD
+without the GPL v2 option. This was done to allow simpler licensing
+terms to be used in the future. It should be noted that the modified BSD
 license is compatible with GNU GPL and as such, this possible move to
 simpler licensing option does not prevent use of this software in
 GPL projects.
@@ -72,7 +80,7 @@ unfortunately be accepted.
 
 Modified BSD license (no advertisement clause):
 
-Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 14f5453..8a98582 100644 (file)
--- a/COPYING
+++ b/COPYING
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
+wpa_supplicant and hostapd
+--------------------------
 
- 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.
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
 
-                           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.
+See the README file for the current license terms.
 
-  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.
+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.
 
-  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.
-\f
-                   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.)
-\f
-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.
-\f
-  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.
-\f
-  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
-\f
-           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.
+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.
diff --git a/README b/README
index 186e4b9..b0f2e6e 100644 (file)
--- a/README
+++ b/README
@@ -1,12 +1,11 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
-These programs are dual-licensed under both the GPL version 2 and BSD
-license (the one with advertisement clause removed). Either license
-may be used at your option.
+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.
@@ -26,26 +25,8 @@ builds).
 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:
+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
diff --git a/build_nsis.sh b/build_nsis.sh
deleted file mode 100755 (executable)
index e41bc36..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-if [ -d nsis.in ]; then
-       /bin/rm -r nsis.in
-fi
-
-unzip -j -d nsis.in $1
-VER=`echo $1 | sed "s/.*wpa_supplicant-windows-bin-\(.*\).zip/\1/"`
-
-cat wpa_supplicant/wpa_supplicant.nsi |
-       sed "s/@WPAVER@/$VER/g" \
-       > nsis.in/wpa_supplicant.nsi
-
-makensis nsis.in/wpa_supplicant.nsi
-
-/bin/rm -r nsis.in
index 22dcd42..dddf92b 100755 (executable)
@@ -1,11 +1,9 @@
 #!/bin/sh
 
-WINLOCAL=/home/jm/H-win/local
-
 set -e
 
 if [ -z "$1" ]; then
-    echo "build_release <version> [nobin]"
+    echo "build_release <version>"
     exit 1
 fi
 
@@ -47,102 +45,3 @@ rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
 tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
 cd ..
 rm -r $TMP
-
-if [ "$2" = "nobin" ]; then
-    exit 0
-fi
-
-
-cd $RELDIR
-
-    PDIR=wpa_supplicant-$VER
-    WDIR=wpa_supplicant-windows-bin-$VER
-    tar xzf $PDIR.tar.gz
-    mkdir "$WDIR"
-    cd "$PDIR/wpa_supplicant"
-    cat > .config <<EOF
-CONFIG_DRIVER_NDIS=y
-CONFIG_NATIVE_WINDOWS=y
-
-CC=i586-mingw32msvc-gcc
-STRIP=i586-mingw32msvc-strip
-PLATFORMSDKLIB=$WINLOCAL/lib
-CONFIG_NDIS_EVENTS_INTEGRATED=y
-
-CFLAGS += -I$WINLOCAL/include
-LIBS += -L$WINLOCAL/lib
-LIBS_w += -L$WINLOCAL/lib
-LIBS_p += -L$WINLOCAL/lib
-
-CONFIG_EAP_SIM=y
-CONFIG_SIM_SIMULATOR=y
-CONFIG_EAP_AKA=y
-CONFIG_USIM_SIMULATOR=y
-CONFIG_EAP_LEAP=y
-CONFIG_EAP_FAST=y
-CONFIG_EAP_TLS=y
-
-CONFIG_CTRL_IFACE=y
-CONFIG_EAP_FAST=y
-CONFIG_EAP_MSCHAPV2=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_MD5=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_OTP=y
-CONFIG_EAP_PAX=y
-CONFIG_EAP_SAKE=y
-CONFIG_EAP_PSK=y
-CONFIG_EAP_TNC=y
-CONFIG_PKCS12=y
-CONFIG_PCSC=y
-CONFIG_WPS=y
-
-CONFIG_L2_PACKET=winpcap
-CONFIG_MAIN=main_winsvc
-CONFIG_BACKEND=winreg
-CONFIG_ELOOP=eloop_win
-CFLAGS += -DCONFIG_DEBUG_FILE
-EOF
-
-    # First, build the Windows service & registry version and rename it
-    make -j2 windows-bin
-    mv wpa_supplicant.exe wpasvc.exe
-
-    # Then, build "the standard" wpa_supplicant.exe
-    cat >> .config <<EOF
-CONFIG_MAIN=main
-CONFIG_BACKEND=file
-EOF
-
-    make -j2 windows-bin
-
-    for i in COPYING; do
-       unix2dos < ../$i > ../../"$WDIR"/$i
-    done
-    for i in README README-Windows.txt wpa_supplicant.conf; do
-       unix2dos < $i > ../../"$WDIR"/$i
-    done
-    mv *.exe ../../"$WDIR"
-    cp win_example.reg ../../"$WDIR"
-
-    cd wpa_gui-qt4
-    make -C icons
-    qmake -spec win32-x-g++
-    make -j2
-    cp release/wpa_gui.exe ../../../"$WDIR"
-    lrelease wpa_gui.pro
-    cp lang/wpa_gui_de.qm ../../../"$WDIR"
-    cd ../../..
-    rm -rf "$PDIR"
-    zip "$WDIR.zip" "$WDIR"/*
-    rm -rf "$WDIR"
-
-cd $RELDIR/..
-
-./build_nsis.sh "$RELDIR/$WDIR.zip"
-mv wpa_supplicant-$VER.exe $RELDIR
-
-ls -l $RELDIR/*$VER*
-
-exit 0
index 27142c3..7590798 100644 (file)
@@ -41,7 +41,7 @@
 
 
 # Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
+#CONFIG_DRIVER_HOSTAP=y
 
 # Driver interface for Agere driver
 #CONFIG_DRIVER_HERMES=y
@@ -471,5 +471,5 @@ CONFIG_IEEE80211N=y
 
 #Additional flags
 CONFIG_LIBNL20=y
-CONFIG_P2P=y
+#CONFIG_P2P=y
 CONFIG_AP=y
index 63a8453..cc597d3 100644 (file)
@@ -41,7 +41,7 @@
 
 
 # Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
+#CONFIG_DRIVER_HOSTAP=y
 
 # Driver interface for Agere driver
 #CONFIG_DRIVER_HERMES=y
@@ -83,7 +83,7 @@ CONFIG_DRIVER_HOSTAP=y
 # 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
+#CONFIG_DRIVER_WEXT=y
 
 # Driver interface for Linux drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
@@ -130,22 +130,22 @@ CONFIG_LIBNL20=y
 
 # Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
 # included)
-CONFIG_IEEE8021X_EAPOL=y
+#CONFIG_IEEE8021X_EAPOL=y
 
 # EAP-MD5
-CONFIG_EAP_MD5=y
+#CONFIG_EAP_MD5=y
 
 # EAP-MSCHAPv2
-CONFIG_EAP_MSCHAPV2=y
+#CONFIG_EAP_MSCHAPV2=y
 
 # EAP-TLS
-CONFIG_EAP_TLS=y
+#CONFIG_EAP_TLS=y
 
 # EAL-PEAP
-CONFIG_EAP_PEAP=y
+#CONFIG_EAP_PEAP=y
 
 # EAP-TTLS
-CONFIG_EAP_TTLS=y
+#CONFIG_EAP_TTLS=y
 
 # EAP-FAST
 # Note: Default OpenSSL package does not include support for all the
@@ -155,10 +155,10 @@ CONFIG_EAP_TTLS=y
 #CONFIG_EAP_FAST=y
 
 # EAP-GTC
-CONFIG_EAP_GTC=y
+#CONFIG_EAP_GTC=y
 
 # EAP-OTP
-CONFIG_EAP_OTP=y
+#CONFIG_EAP_OTP=y
 
 # EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
 #CONFIG_EAP_SIM=y
@@ -170,7 +170,7 @@ CONFIG_EAP_OTP=y
 #CONFIG_EAP_PAX=y
 
 # LEAP
-CONFIG_EAP_LEAP=y
+#CONFIG_EAP_LEAP=y
 
 # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
 #CONFIG_EAP_AKA=y
@@ -208,11 +208,11 @@ CONFIG_WPS2=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
+#CONFIG_PKCS12=y
 
 # Smartcard support (i.e., private key on a smartcard), e.g., with openssl
 # engine.
-CONFIG_SMARTCARD=y
+#CONFIG_SMARTCARD=y
 
 # PC/SC interface for smartcards (USIM, GSM SIM)
 # Enable this if EAP-SIM or EAP-AKA is included
@@ -368,10 +368,10 @@ CONFIG_TLS=openssl
 
 # Add support for new DBus control interface
 # (fi.w1.hostap.wpa_supplicant1)
-CONFIG_CTRL_IFACE_DBUS_NEW=y
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
 
 # Add introspection support for new DBus control interface
-CONFIG_CTRL_IFACE_DBUS_INTRO=y
+#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
@@ -469,3 +469,7 @@ CONFIG_IEEE80211N=y
 # external networks (GAS/ANQP to learn more about the networks and network
 # selection based on available credentials).
 #CONFIG_INTERWORKING=y
+
+CONFIG_NO_RADIUS=y
+CONFIG_AP=y
+TIZEN_EXT=y
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644 (file)
index cceb592..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-wpasupplicant (0.8.0-0slp2+7) unstable; urgency=low
-
-  * Enable debug log for developers
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+7
-
- -- Danny Jeongseok Seo <s.seo@samsung.com>  Thu, 22 Mar 2012 20:30:36 +0900
-
-wpasupplicant (0.8.0-0slp2+6) unstable; urgency=low
-
-  * Send disconnect to a driver for bcm4330 when a disassoc event is coming
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+6
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Tue, 20 Mar 2012 21:48:45 +0900
-
-wpasupplicant (0.8.0-0slp2+5) unstable; urgency=low
-
-  * Revise spec for OBS and build script
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+5
-
- -- Danny Jeongseok Seo <s.seo@samsung.com>  Sat, 17 Mar 2012 18:18:35 +0900
-
-wpasupplicant (0.8.0-0slp2+4) unstable; urgency=low
-
-  * Skip specific scan after coming disassoc event
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+4
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Fri, 16 Mar 2012 17:58:24 +0900
-
-wpasupplicant (0.8.0-0slp2+3) unstable; urgency=low
-
-  * Add dependency for a libnl2 pkg
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+3
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Mon, 05 Mar 2012 20:01:31 +0900
-
-wpasupplicant (0.8.0-0slp2+2) unstable; urgency=low
-
-  * Make debug level from MSG_INFO to MSG_EXCESSIVE temporally
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+2
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Mon, 05 Mar 2012 13:27:09 +0900
-
-wpasupplicant (0.8.0-0slp2+1) unstable; urgency=low
-
-  * Update wpasupplicant from 0.7.3 to 0.8.x
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.8.0-0slp2+1
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Mon, 05 Mar 2012 10:54:18 +0900
-
-wpasupplicant (0.7.3-0slp2+4) unstable; urgency=low
-
-  * Modify the way to set dbus access authority
-  * According to security plicy, change to use ID from string
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.7.3-0slp2+4
-
- -- Sanghoon Cho <sanghoon80.cho@samsung.com>  Tue, 17 Jan 2012 17:20:03 +0900
-
-wpasupplicant (0.7.3-0slp2+3) unstable; urgency=low
-
-  * Release wpasupplicant_0.7.3-0slp2+3
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.7.3-0slp2+3
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Thu, 22 Dec 2011 17:12:17 +0900
-
-wpasupplicant (0.7.3-0slp2+2) unstable; urgency=low
-
-  * Fix supplicant's associating state bug
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.7.3-0slp2+2
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Tue, 06 Dec 2011 22:48:42 +0900
-
-wpasupplicant (0.7.3-0slp2+1) unstable; urgency=low
-
-  * TIZEN workaround fix for connman
-  * Git: pkgs/w/wpasupplicant
-  * Tag: wpasupplicant_0.7.3-0slp2+1
-
- -- Sunkey Lee <yuvjjang.lee@samsung.com>  Thu, 22 Sep 2011 19:34:23 +0900
-
-wpasupplicant (0.7.3-0slp2) unstable; urgency=low
-
-  * upgrade to 0.7.3
-
- -- Jongmin Lee <jm105.lee@samsung.com>  Thu, 16 Sep 2010 16:15:42 +0900
-
-wpasupplicant (0.6.10-0slp2) unstable; urgency=low
-
-  * debianlize
-
- -- Jongmin Lee <jm105.lee@samsung.com>  Tue, 20 Jul 2010 09:00:00 +0900
diff --git a/debian/compat b/debian/compat
deleted file mode 100644 (file)
index 7ed6ff8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-5
diff --git a/debian/control b/debian/control
deleted file mode 100644 (file)
index 4abe922..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Source: wpasupplicant
-Section: net
-Priority: optional
-Maintainer: Sunkey Lee <yuvjjang.lee@samsung.com>, Danny Jeongseok Seo <s.seo@samsung.com>
-Uploaders: Sunkey Lee <yuvjjang.lee@samsung.com>, Misun Kim <ms0123.kim@samsung.com>, Sanghoon Cho <sanghoon80.cho@samsung.com>
-Build-Depends: debhelper (>= 5), libssl-dev, libdbus-1-dev, pkg-config, libnl2-dev
-Standards-Version: 0.1.0
-
-Package: wpasupplicant
-Section: net
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
-Replaces: libwpasupplicant-0
-Description: client support for WPA and WPA2 (IEEE 802.11i)
- WPA and WPA2 are methods for securing wireless networks, the former
- using IEEE 802.1X, and the latter using IEEE 802.11i. This software
- provides key negotiation with the WPA Authenticator, and controls
- association with IEEE 802.11i networks.
-
-Package: wpasupplicant-dbg
-Section: debug
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
-Replaces: libwpasupplicant-0
-Description: Debugging symbols for wpasupplicant
- wpasupplicant is client support for WPA and WPA2 (IEEE 802.11i).
- WPA and WPA2 are methods for securing wireless networks, the former
- using IEEE 802.1X, and the latter using IEEE 802.11i. This software
- provides key negotiation with the WPA Authenticator, and controls
- association with IEEE 802.11i networks.
diff --git a/debian/rules b/debian/rules
deleted file mode 100755 (executable)
index c673255..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-
-# These are used for cross-compiling and for saving the configure script
-# from having to guess our platform (since we know it already)
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-
-CFLAGS ?= -Wall -g
-LDFLAGS ?=
-PREFIX ?= /usr
-DATADIR ?= /opt
-
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
-       CFLAGS += -O0
-else
-       CFLAGS += -O2
-endif
-
-LDFLAGS += -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed
-CONFIG := configurations/tizen.config
-HOST_CONFIG := configurations/tizen_hostapd.config
-#WPAGUI = wpa_gui-qt4
-
-config.status: configure
-       dh_testdir
-       # Add here commands to configure the package.
-       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --prefix=$(PREFIX)
-
-build: build-stamp
-build-stamp:
-       dh_testdir
-
-       # wpa_supplicant
-       cp -v $(CONFIG) wpa_supplicant/.config
-       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) -C wpa_supplicant all
-
-       # hostapd
-       $(MAKE) -C hostapd clean
-       #cp -v $(HOST_CONFIG) hostapd/.config
-       #       CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) -C hostapd all
-
-       # wpa_gui
-       #$(MAKE) -C wpa_supplicant $(WPAGUI)
-
-       # manpages
-       #$(MAKE) -C wpa_supplicant/doc/docbook man
-
-       for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
-               cat $$f > $${f%.in}; \
-               sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \
-               sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \
-       done
-
-       touch $@
-
-clean:
-       dh_testdir
-       dh_testroot
-
-       $(MAKE) -C wpa_supplicant clean
-       #$(MAKE) -C hostapd clean
-
-       #if [ -f wpa_supplicant/$(WPAGUI)/Makefile ]; then \
-       #       $(MAKE) -C wpa_supplicant/$(WPAGUI) distclean ; \
-       #fi
-
-       #$(MAKE) -C wpa_supplicant/doc/docbook clean
-
-       #dh_clean wpa_supplicant/.config hostapd/.config build-stamp install-stamp
-       dh_clean wpa_supplicant/.config build-stamp install-stamp
-
-       for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
-               rm -f $${f%.in}; \
-       done
-
-       rm -f ../wpasupplicant_*.deb
-       rm -f ../wpasupplicant-*.deb
-       rm -f ../wpasupplicant_*.changes
-       rm -f ../wpasupplicant_*.dsc
-       rm -f ../wpasupplicant_*.tar.gz
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k
-       dh_installdirs
-       dh_install
-
-       # Add here commands to install the package into debian/ncurses.
-       #$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
-
-       # D-Bus
-       install --mode=644 -D wpa_supplicant/dbus/dbus-wpa_supplicant.conf \
-               debian/wpasupplicant/$(PREFIX)/etc/dbus-1/system.d/wpa_supplicant.conf
-       install --mode=644 -D wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service \
-               debian/wpasupplicant/$(PREFIX)/share/dbus-1/services/fi.epitest.hostap.WPASupplicant.service
-       install --mode=644 -D wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service \
-               debian/wpasupplicant/$(PREFIX)/share/dbus-1/services/fi.w1.wpa_supplicant1.service
-       install --mode=755 -D etc/rc.d/init.d/wpa_supplicant \
-               debian/wpasupplicant/etc/rc.d/init.d/wpa_supplicant
-       mkdir -p debian/wpasupplicant/etc/rc.d/rc3.d/
-       ln -s ../init.d/wpa_supplicant debian/wpasupplicant/etc/rc.d/rc3.d/S62wpasupplicant
-       mkdir -p debian/wpasupplicant/etc/rc.d/rc5.d/
-       ln -s ../init.d/wpa_supplicant debian/wpasupplicant/etc/rc.d/rc5.d/S62wpasupplicant
-
-       # sanitise the example configuration
-       mkdir -p debian/wpasupplicant/$(PREFIX)/share/doc/wpasupplicant
-       sed 's/^\([^#]\+=.*\|}\)/#\1/' < wpa_supplicant/wpa_supplicant.conf \
-               > debian/wpasupplicant/$(PREFIX)/share/doc/wpasupplicant/README.wpa_supplicant.conf
-
-
-
-# Build architecture-independent files here.
-binary-indep: build install
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: build install
-       dh_testdir
-       dh_testroot
-#      dh_installchangelogs
-#      dh_installdocs
-#      dh_installexamples
-#      dh_install --sourcedir=debian/tmp
-#      dh_installmenu
-#      dh_installdebconf
-#      dh_installlogrotate
-#      dh_installemacsen
-#      dh_installpam
-#      dh_installmime
-#      dh_python
-#      dh_installinit
-#      dh_installcron
-#      dh_installinfo
-#      dh_installman
-       dh_link
-       dh_strip -a --dbg-package=wpasupplicant-dbg
-       dh_compress
-       dh_fixperms
-#      dh_perl
-       dh_makeshlibs
-       dh_installdeb
-       dh_shlibdeps
-       dh_gencontrol
-       dh_md5sums
-       dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/wpasupplicant.install.in b/debian/wpasupplicant.install.in
deleted file mode 100644 (file)
index a07f514..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-wpa_supplicant/wpa_supplicant @PREFIX@/sbin/
-wpa_supplicant/wpa_cli @PREFIX@/sbin/
-#hostapd/hostapd @PREFIX@/sbin/
-#hostapd/hostapd_cli @PREFIX@/sbin/
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644 (file)
index 0000000..28c3fe4
--- /dev/null
@@ -0,0 +1,14 @@
+doxygen.warnings
+hostapd.eps
+hostapd.png
+html
+latex
+p2p_arch.eps
+p2p_arch.png
+p2p_arch2.eps
+p2p_arch2.png
+p2p_sm.eps
+p2p_sm.png
+wpa_supplicant.eps
+wpa_supplicant.png
+wpa_supplicant-devel.pdf
index 5c1b386..4e1c1bd 100644 (file)
@@ -7,20 +7,33 @@ all: docs
        fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
                > $*.png
 
-docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps
+%.png: %.dot
+       dot $*.dot -Tpng -o $*.png
+
+%.eps: %.dot
+       dot $*.dot -Tps -o $*.eps
+
+_wpa_supplicant.png: wpa_supplicant.png
+       cp $< $@
+
+docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps
 
 docs: docs-pics
        (cd ..; doxygen doc/doxygen.conf; cd doc)
        $(MAKE) -C latex
        cp latex/refman.pdf wpa_supplicant-devel.pdf
 
-html: docs-pics
+html: docs-pics _wpa_supplicant.png
        (cd ..; doxygen doc/doxygen.conf; cd doc)
 
 clean:
        rm -f *~
        rm -f wpa_supplicant.eps wpa_supplicant.png
+       rm -f _wpa_supplicant.png
        rm -f hostapd.eps hostapd.png
+       rm -f p2p_sm.eps p2p_sm.png
+       rm -f p2p_arch.eps p2p_arch.png
+       rm -f p2p_arch2.eps p2p_arch2.png
        rm -f doxygen.warnings
        rm -rf html latex
        rm -f wpa_supplicant-devel.pdf
index 96f6160..26f5f6d 100644 (file)
@@ -1,7 +1,7 @@
 /**
 \page code_structure Structure of the source code
 
-[ \ref wpa_supplicant_core "wpa_supplicant core functionality" |
+[ \ref _wpa_supplicant_core "wpa_supplicant core functionality" |
 \ref generic_helper_func "Generic helper functions" |
 \ref crypto_func "Cryptographic functions" |
 \ref tls_func "TLS library" |
@@ -29,7 +29,7 @@ all hardware/driver dependent functionality is implemented in
 driver_*.c.
 
 
-\section wpa_supplicant_core wpa_supplicant core functionality
+\section _wpa_supplicant_core wpa_supplicant core functionality
 
 wpa_supplicant.c
        Program initialization, main control loop
index f820f9e..0d06625 100644 (file)
@@ -1012,8 +1012,8 @@ P2P-PROV-DISC-PBC-RESP 02:40:61:c2:f3:b7
 
 P2P-SERV-DISC-REQ: Indicate reception of a P2P service discovery
 request. The following parameters are included after the event prefix:
-frequency in MHz, source address, dialog token, Service Query TLV(s) as
-hexdump.
+frequency in MHz, source address, dialog token, Service Update
+Indicator, Service Query TLV(s) as hexdump.
 
 \verbatim
 P2P-SERV-DISC-REQ 2412 02:40:61:c2:f3:b7 0 0 02000001
@@ -1023,7 +1023,8 @@ P2P-SERV-DISC-REQ 2412 02:40:61:c2:f3:b7 0 0 02000001
 
 P2P-SERV-DISC-RESP: Indicate reception of a P2P service discovery
 response. The following parameters are included after the event prefix:
-source address, dialog token, Service Response TLV(s) as hexdump.
+source address, Service Update Indicator, Service Response TLV(s) as
+hexdump.
 
 \verbatim
 P2P-SERV-DISC-RESP 02:40:61:c2:f3:b7 0 0300000101
index eeea200..1fa7a3a 100644 (file)
@@ -316,6 +316,30 @@ fi.w1.wpa_supplicant1.CreateInterface.
          <dd>A blob with the specified name doesn't exist.</dd>
        </dl>
       </li>
+      <li>
+       <h3>AutoScan ( s : arg ) --> nothing</h3>
+       <p>Set autoscan parameters for the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : arg</dt>
+         <dd>Autoscan parameter line or empty to unset autoscan.</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+         <dd>Needed memory was not possible to get allocated.</dd>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
+      <li>
+       <h3>EAPLogoff ( ) --> nothing</h3>
+       <p>IEEE 802.1X EAPOL state machine logoff.</p>
+      </li>
+      <li>
+       <h3>EAPLogon ( ) --> nothing</h3>
+       <p>IEEE 802.1X EAPOL state machine logon.</p>
+      </li>
     </ul>
 
 \subsection dbus_interface_properties Properties
@@ -352,6 +376,21 @@ fi.w1.wpa_supplicant1.CreateInterface.
       </li>
 
       <li>
+       <h3>BSSExpireAge - u - (read/write)</h3>
+       <p>Identical to bss_expiration_age entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+       <h3>BSSExpireCount - u - (read/write)</h3>
+       <p>Identical to bss_expiration_scan_count entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+       <h3>Country - s - (read/write)</h3>
+       <p>Identical to country entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
        <h3>Ifname - s - (read)</h3>
        <p>Name of network interface controlled by the interface, e.g., wlan0.</p>
       </li>
@@ -390,6 +429,16 @@ fi.w1.wpa_supplicant1.CreateInterface.
        <h3>Networks - ao - (read)</h3>
        <p>List of D-Bus objects paths representing configured networks.</p>
       </li>
+
+      <li>
+       <h3>FastReauth - b - (read/write)</h3>
+       <p>Identical to fast_reauth entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+       <h3>ScanInterval - i - (read/write)</h3>
+       <p>Time (in seconds) between scans for a suitable AP. Must be >= 0.</p>
+      </li>
     </ul>
 
 \subsection dbus_interface_signals Signals
@@ -484,6 +533,26 @@ fi.w1.wpa_supplicant1.CreateInterface.
       </li>
 
       <li>
+       <h3>StaAuthorized ( s : mac )</h3>
+       <p>A new station has been authorized to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : mac</dt>
+         <dd>A mac address which has been authorized.</dd>
+       </dl>
+      </li>
+
+      <li>
+       <h3>StaDeauthorized ( s : mac )</h3>
+       <p>A station has been deauthorized to the interface.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>s : mac</dt>
+         <dd>A mac address which has been deauthorized.</dd>
+       </dl>
+      </li>
+
+      <li>
        <h3>PropertiesChanged ( a{sv} : properties )</h3>
        <p>Some properties have changed.</p>
        <h4>Arguments</h4>
index 6a1cb3e..b8c40e3 100644 (file)
@@ -25,13 +25,13 @@ DOXYFILE_ENCODING      = UTF-8
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
 # by quotes) that should identify the project.
 
-PROJECT_NAME           = wpa_supplicant / hostapd
+PROJECT_NAME           = "wpa_supplicant / hostapd"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = 0.7.x
+PROJECT_NUMBER         = 2.0
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
@@ -582,6 +582,7 @@ INPUT                  = \
        src/eap_peer \
        src/eap_server \
        src/l2_packet \
+       src/p2p \
        src/radius \
        src/rsn_supp \
        src/tls \
@@ -1277,7 +1278,7 @@ INCLUDE_FILE_PATTERNS  =
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             = IEEE8021X_EAPOL CONFIG_CTRL_IFACE
+PREDEFINED             = IEEE8021X_EAPOL CONFIG_CTRL_IFACE CONFIG_P2P
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
index 690b7d6..26dc929 100644 (file)
@@ -8,10 +8,10 @@ modified, how new drivers can be supported, and how the source code
 can be ported to other operating systems. If any information is
 missing, feel free to contact Jouni Malinen <j@w1.fi> for more
 information. Contributions as patch files are also very welcome at the
-same address. Please note that this software is licensed under dual
-license, GPLv2 or BSD at user's choice. All contributions to
-%wpa_supplicant and hostapd are expected to use compatible licensing
-terms.
+same address. Please note that this software is licensed under the
+BSD license (the one with advertisement clause removed). All
+contributions to %wpa_supplicant and hostapd are expected to use
+compatible licensing terms.
 
 The source code and read-only access to the combined %wpa_supplicant
 and hostapd Git repository is available from the project home page at
@@ -20,7 +20,7 @@ available as a PDF file from
 http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
 
 
-\section wpa_supplicant wpa_supplicant
+\section _wpa_supplicant wpa_supplicant
 
 %wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
 support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
@@ -54,11 +54,11 @@ daemon and to get status information and event notifications. There is
 a small C library that provides helper functions to facilitate the use of the
 control interface. This library can also be used with C++.
 
-\image html wpa_supplicant.png "wpa_supplicant modules"
-\image latex wpa_supplicant.eps "wpa_supplicant modules" width=15cm
+\image html _wpa_supplicant.png "wpa_supplicant modules"
+\image latex _wpa_supplicant.eps "wpa_supplicant modules" width=15cm
 
 
-\section hostapd hostapd
+\section _hostapd hostapd
 
 hostapd includes IEEE 802.11 access point management (authentication /
 association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
diff --git a/doc/p2p.doxygen b/doc/p2p.doxygen
new file mode 100644 (file)
index 0000000..6b11e56
--- /dev/null
@@ -0,0 +1,498 @@
+/**
+\page p2p Wi-Fi Direct - P2P module
+
+Wi-Fi Direct functionality is implemented any many levels in the WLAN
+stack from low-level driver operations to high-level GUI design. This
+document covers the parts that can be user by %wpa_supplicant. However,
+it should be noted that alternative designs are also possible, so some
+of the functionality may reside in other components in the system.
+
+The driver (or WLAN firmware/hardware) is expected to handle low-level
+operations related to P2P Power Management and channel scheduling. In
+addition, support for virtual network interface and data frame
+processing is done inside the driver. Configuration for these
+low-level operations is defined in the driver interface:
+src/drivers/driver.h. This defines both the commands and events used to
+interact with the driver.
+
+P2P module implements higher layer functionality for management P2P
+groups. It takes care of Device Discovery, Service Discovery, Group
+Owner Negotiation, P2P Invitation. In addition, it maintains
+information about neighboring P2P Devices. This module could be used
+in designs that do not use %wpa_supplicant and it could also reside
+inside the driver/firmware component. P2P module API is defined in
+src/p2p/p2p.h.
+
+Provisioning step of Group Formation is implemented using WPS
+(src/wps/wps.h).
+
+%wpa_supplicant includes code in interact with both the P2P module
+(wpa_supplicant/p2p_supplicant.c) and WPS
+(wpa_supplicant/wps_supplicant.c). The driver operations are passed
+through these files, i.e., core P2P or WPS code does not interact
+directly with the driver interface.
+
+
+\section p2p_arch P2P architecture
+
+P2P functionality affects many areas of the system architecture. This
+section shows couple of examples on the location of main P2P
+components. In the diagrams below, green arrows are used to show
+communication paths from the P2P module to upper layer management
+functionality and all the way to a GUI that user could use to manage
+P2P connections. Blue arrows show the path taken for lower layer
+operations. Glue code is used to bind the P2P module API to the rest
+of the system to provide access both towards upper and lower layer
+functionality.
+
+\subsection p2p_arch_mac80211 P2P architecture with Linux/mac80211/ath9k
+
+An architecture where the P2P module resides inside the
+%wpa_supplicant process is used with Linux mac80211-based drivers,
+e.g., ath9k. The following diagram shows the main components related
+to P2P functionality in such an architecture.
+
+\image html p2p_arch.png "P2P module within wpa_supplicant"
+\image latex p2p_arch.eps "P2P module within wpa_supplicant" width=15cm
+
+\subsection p2p_arch_umac P2P architecture with UMAC
+
+The following diagram shows the main components related to P2P
+functionality in an architecture where the P2P module resides inside
+the kernel IEEE 802.11 stack (UMAC in the figure).
+
+\image html p2p_arch2.png "P2P module in kernel
+\image latex p2p_arch2.eps "P2P module in kernel" width=15cm
+
+
+\section p2p_module P2P module
+
+P2P module manages discovery and group formation with a single state
+machine, i.e., only a single operation per device can be in progress
+at any given time. The following diagram describes the P2P state
+machine. For clarity, it does not include state transitions on
+operation timeouts to the IDLE state. The states that are marked with
+dotted ellipse are listed for clarity to describe the protocol
+functionality for Device Discovery phase, but are not used in the
+implementation (the SEARCH state is used to manage the initial Scan
+and the alternating Listen and Search states within Find).
+
+\image html p2p_sm.png "P2P module state machine"
+\image latex p2p_sm.eps "P2P module state machine" width=15cm
+
+\subsection p2p_module_api P2P module API
+
+P2P module API is defined in src/p2p/p2p.h. The API consists of
+functions for requesting operations and for providing event
+notifications. Similar set of callback functions are configured with
+struct p2p_config to provide callback functions that P2P module can
+use to request operations and to provide event notifications. In
+addition, there are number of generic helper functions that can be
+used for P2P related operations.
+
+These are the main functions for an upper layer management entity to
+request P2P operations:
+- p2p_find()
+- p2p_stop_find()
+- p2p_listen()
+- p2p_connect()
+- p2p_reject()
+- p2p_prov_disc_req()
+- p2p_sd_request()
+- p2p_sd_cancel_request()
+- p2p_sd_response()
+- p2p_sd_service_update()
+- p2p_invite()
+
+These are the main callback functions for P2P module to provide event
+notifications to the upper layer management entity:
+
+- p2p_config::dev_found()
+- p2p_config::go_neg_req_rx()
+- p2p_config::go_neg_completed()
+- p2p_config::sd_request()
+- p2p_config::sd_response()
+- p2p_config::prov_disc_req()
+- p2p_config::prov_disc_resp()
+- p2p_config::invitation_process()
+- p2p_config::invitation_received()
+- p2p_config::invitation_result()
+
+The P2P module uses following functions to request lower layer driver
+operations:
+
+- p2p_config::p2p_scan()
+- p2p_config::send_probe_resp()
+- p2p_config::send_action()
+- p2p_config::send_action_done()
+- p2p_config::start_listen()
+- p2p_config::stop_listen()
+
+Events from lower layer driver operations are delivered to the P2P
+module with following functions:
+
+- p2p_probe_req_rx()
+- p2p_rx_action()
+- p2p_scan_res_handler()
+- p2p_scan_res_handled()
+- p2p_send_action_cb()
+- p2p_listen_cb()
+
+In addition to the per-device state, the P2P module maintains
+per-group state for group owners. This is initialized with a call to
+p2p_group_init() when a group is created and deinitialized with
+p2p_group_deinit(). The upper layer GO management entity uses
+following functions to interact with the P2P per-group state:
+
+- p2p_group_notif_assoc()
+- p2p_group_notif_disassoc()
+- p2p_group_notif_formation_done()
+- p2p_group_match_dev_type()
+
+The P2P module will use following callback function to update P2P IE
+for GO Beacon and Probe Response frames:
+
+- p2p_group_config::ie_update()
+
+
+\section p2p_driver P2P driver operations (low-level interface)
+
+The following driver wrapper functions are needed for P2P in addition
+to the standard station/AP mode operations when the P2P module resides
+within %wpa_supplicant:
+- wpa_driver_ops::if_add()
+- wpa_driver_ops::if_remove()
+- wpa_driver_ops::alloc_interface_addr()
+- wpa_driver_ops::release_interface_addr()
+- wpa_driver_ops::remain_on_channel()
+- wpa_driver_ops::cancel_remain_on_channel()
+- wpa_driver_ops::send_action()
+- wpa_driver_ops::probe_req_report()
+- wpa_driver_ops::disable_11b_rates()
+
+The following driver wrapper events are needed for P2P in addition to
+the standard station/AP mode events when the P2P module resides within
+%wpa_supplicant:
+- wpa_event_type::EVENT_RX_ACTION
+- wpa_event_type::EVENT_REMAIN_ON_CHANNEL
+- wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
+- wpa_event_type::EVENT_RX_PROBE_REQ
+
+The following driver wrapper functions are needed for P2P in addition
+to the standard station/AP mode operations when the P2P module resides
+in the driver or firmware:
+- wpa_driver_ops::if_add()
+- wpa_driver_ops::if_remove()
+- wpa_driver_ops::alloc_interface_addr()
+- wpa_driver_ops::release_interface_addr()
+- wpa_driver_ops::disable_11b_rates()
+- wpa_driver_ops::p2p_find()
+- wpa_driver_ops::p2p_stop_find()
+- wpa_driver_ops::p2p_listen()
+- wpa_driver_ops::p2p_connect()
+- wpa_driver_ops::p2p_reject()
+- wpa_driver_ops::wps_success_cb()
+- wpa_driver_ops::p2p_group_formation_failed()
+- wpa_driver_ops::p2p_set_params()
+
+The following driver wrapper events are needed for P2P in addition to
+the standard station/AP mode events when the P2P module resides in the
+driver or firmware:
+- wpa_event_type::EVENT_P2P_DEV_FOUND
+- wpa_event_type::EVENT_P2P_GO_NEG_REQ_RX
+- wpa_event_type::EVENT_P2P_GO_NEG_COMPLETED
+
+
+\section p2p_go_neg P2P device discovery and group formation
+
+This section shows an example sequence of operations that can be used
+to implement P2P device discovery and group formation. The function
+calls are described based on the P2P module API. The exact design for
+the glue code outside the P2P module depends on the architecture used
+in the system.
+
+An upper layer management entity starts P2P device discovery by
+calling p2p_find(). The P2P module start the discovery by requesting a
+full scan to be completed by calling p2p_config::p2p_scan(). Results
+from the scan will be reported by calling p2p_scan_res_handler() and
+after last result, the scan result processing is terminated with a
+call to p2p_scan_res_handled(). The P2P peers that are found during
+the full scan are reported with the p2p_config::dev_found() callback.
+
+After the full scan, P2P module start alternating between Listen and
+Search states until the device discovery operation times out or
+terminated, e.g., with a call to p2p_stop_find().
+
+When going into the Listen state, the P2P module requests the driver
+to be configured to be awake on the listen channel with a call to
+p2p_config::start_listen(). The glue code using the P2P module may
+implement this, e.g., by using remain-on-channel low-level driver
+functionality for off-channel operation. Once the driver is available
+on the requested channel, notification of this is delivered by calling
+p2p_listen_cb(). The Probe Request frames that are received during the
+Listen period are delivered to the P2P module by calling
+p2p_config::p2p_probe_req_rx() and P2P module request a response to
+these to be sent by using p2p_config::send_probe_resp() callback
+function. If a group owner negotiation from another P2P device is
+received during the device discovery phase, that is indicated to the
+upper layer code with the p2p_config::go_neg_req_tx() callback.
+
+The Search state is implemented by using the normal scan interface,
+i.e., the P2P module will call p2p_config::p2p_scan() just like in the
+full scan phase described. Similarly, scan results from the search
+operation will be delivered to the P2P module using the
+p2p_scan_res_handler() and p2p_scan_res_handled() functions.
+
+Once the upper layer management entity has found a peer with which it
+wants to connect by forming a new group, it initiates group owner
+negotiation by calling p2p_connect(). Before doing this, the upper
+layer code is responsible for asking the user to provide the PIN to be
+used during the provisioning step with the peer or the push button
+press for PBC mode. The glue code will need to figure out the intended
+interface address for the group before group owner negotiation can be
+started.
+
+Optional Provision Discovery mechanism can be used to request the peer
+to display a PIN for the local device to enter (and vice versa). Upper
+layer management entity can request the specific mechanism by calling
+p2p_prov_disc_req(). The response to this will be reported with the
+p2p_config::prov_disc_resp() callback. If the peer device started
+Provision Discovery, an accepted request will be reported with the
+p2p_config::prov_disc_req() callback. The P2P module will
+automatically accept the Provision Discovery for display and keypad
+methods, but it is up to the upper layer manegement entity to actually
+generate the PIN and to configure it with following p2p_connect() call
+to actually authorize the connection.
+
+The P2P module will use p2p_config::send_action() callback to request
+lower layer code to transmit an Action frame during group owner
+negotiation. p2p_send_action_cb() is used to report the result of
+transmission. If the peer is not reachable, the P2P module will try to
+find it by alternating between Action frame send and Listen
+states. The Listen state for this phase will be used similarly to the
+Listen state during device discovery as described above.
+
+Once the group owner negotiation has been completed, its results will
+be reported with the p2p_config::go_neg_completed() callback. The
+upper layer management code or the glue code using the P2P module API
+is responsible for creating a new group interface and starting
+provisioning step at this point by configuring WPS Registrar or
+Enrollee functionality based on the reported group owner negotiation
+results. The upper layer code is also responsible for timing out WPS
+provisioning if it cannot be completed in 15 seconds.
+
+Successful completion of the WPS provisioning is reported with a call
+to p2p_wps_success_cb(). The P2P module will clear its group formation
+state at this point and allows new group formation attempts to be
+started. The upper layer management code is responsible for configuring
+the GO to accept associations from devices and the client to connect to
+the GO with the provisioned credentials. GO is also responsible for
+calling p2p_group_notif_formation_done() as described below.
+
+If the WPS provisioning step fails or times out, this is reported with
+a call to p2p_group_formation_failed(). The P2P module will clear its
+group formation state at this point and allows new group formation
+attempts to be started. The upper layer management code is responsible
+for removing the group interface for the failed group.
+
+
+\section p2p_sd P2P service discovery
+
+P2P protocol includes service discovery functionality that can be used
+to discover which services are provided by the peers before forming a
+group. This leverages the Generic Advertisement Service (GAS) protocol
+from IEEE 802.11u and P2P vendor-specific contents inside the Native
+GAS messages.
+
+The P2P module takes care of GAS encapsulation, fragmentation, and
+actual transmission and reception of the Action frames needed for
+service discovery. The user of the P2P module is responsible for
+providing P2P specific Service Request TLV(s) for queries and Service
+Response TLV(s) for responses.
+
+\subsection p2p_sd_query Quering services of peers
+
+Service discovery is implemented by processing pending queries as a
+part of the device discovery phase. p2p_sd_request() function is used
+to schedule service discovery queries to a specific peer or to all
+discovered peers. p2p_sd_cancel_request() can be used to cancel a
+scheduled query. Queries that are specific to a single peer will be
+removed automatically after the response has been received.
+
+After the service discovery queries have been queued, device discovery
+is started with a call to p2p_find(). The pending service discovery
+queries are then sent whenever a peer is discovered during the find
+operation. Responses to the queries will be reported with the
+p2p_config::sd_response() callback.
+
+\subsection p2p_sd_response Replying to service discovery queries from peers
+
+The received service discovery requests will be indicated with the
+p2p_config::sd_request() callback. The response to the query is sent
+by calling p2p_sd_response().
+
+\subsection p2p_sd_indicator Service update indicator
+
+P2P service discovery provides a mechanism to notify peers about
+changes in available services. This works by incrementing Service
+Update Indicator value whenever there is a change in the
+services. This value is included in all SD request and response
+frames. The value received from the peers will be included in the
+p2p_config::sd_request() and p2p_config::sd_response() callbacks. The
+value to be sent to the peers is incremented with a call to
+p2p_sd_service_update() whenever availibility of the local services
+changes.
+
+
+\section p2p_go P2P group owner
+
+This section describes how P2P module can be used for managing
+per-group information in a group owner. The function calls are
+described based on the P2P module API. The exact design for the glue
+code outside the P2P module depends on the architecture used in the
+system.
+
+When a P2P group interface is created in group owner role, per-group
+data is initialized with p2p_group_init(). This call provides a
+pointer to the per-device P2P module context and configures the
+per-group operation. The configured p2p_group_config::ie_update()
+callback is used to set the initial P2P IE for Beacon and Probe
+Response frames in the group owner. The AP mode implementation may use
+this information to add IEs into the frames.
+
+Once the group formation has been completed (or if it is skipped in
+case of manual group setup), p2p_group_notif_formation_done() is
+called. This will allow the P2P module to update the P2P IE for
+Beacon and Probe Response frames.
+
+The SME/MLME code that managements IEEE 802.11 association processing
+needs to inform P2P module whenever a P2P client associates or
+disassociates with the group. This is done by calling
+p2p_group_notif_assoc() and p2p_group_notif_disassoc(). The P2P module
+manages a list of group members and updates the P2P Group Information
+subelement in the P2P IE based on the information from the P2P
+clients. The p2p_group_config::ie_update() callback is used whenever
+the P2P IE in Probe Response frames needs to be changed.
+
+The SME/MLME code that takes care of replying to Probe Request frames
+can use p2p_group_match_dev_type() to check whether the Probe Request
+frame request a reply only from groups that include a specific device
+type in one of the clients or GO. A match will be reported if the
+Probe Request does not request a specific device type, so this
+function can be used to filter or received Probe Request frames and
+only the ones that result in non-zero return value need to be replied.
+
+When the P2P group interface for GO role is removed,
+p2p_group_deinit() is used to deinitialize the per-group P2P module
+state.
+
+
+\section p2p_ctrl_iface P2P control interface
+
+%wpa_supplicant \ref ctrl_iface_page "control interface" can be used
+to manage P2P functionality from an external program (e.g., a GUI or a
+system configuration manager). This interface can be used directly
+through the control interface backend mechanism (e.g., local domain
+sockets on Linux) or with help of wpa_cli (e.g., from a script).
+
+The following P2P-related commands are available:
+- \ref ctrl_iface_P2P_FIND P2P_FIND
+- \ref ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
+- \ref ctrl_iface_P2P_CONNECT P2P_CONNECT
+- \ref ctrl_iface_P2P_LISTEN P2P_LISTEN
+- \ref ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
+- \ref ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
+- \ref ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
+- \ref ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
+- \ref ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
+- \ref ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
+- \ref ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
+- \ref ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
+- \ref ctrl_iface_P2P_REJECT P2P_REJECT
+- \ref ctrl_iface_P2P_INVITE P2P_INVITE
+
+The following P2P-related events are used:
+- \ref ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED
+- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN
+- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN
+- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ
+- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP
+- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED
+- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT
+
+
+\subsection p2p_wpa_gui GUI example (wpa_gui)
+
+wpa_gui has an example implementation of a GUI that could be used to
+manage P2P operations. The P2P related functionality is contained
+mostly in wpa_supplicant/wpa_gui-qt4/peers.cpp and it shows how the
+control interface commands and events can be used.
+
+
+\subsection p2p_wpa_cli wpa_cli example
+
+wpa_cli can be used to control %wpa_supplicant in interactive
+mode. The following sessions show examples of commands used for
+device discovery and group formation. The lines starting with "> " are
+commands from the user (followed by command result indication) and
+lines starting with "<2>" are event messages from %wpa_supplicant.
+
+P2P device "Wireless Client":
+
+\verbatim
+> p2p_find
+OK
+> <2>P2P-DEVICE-FOUND 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Wireless Client 2' config_methods=0x18c
+dev_capab=0x1 group_capab=0x0
+<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
+<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
+> p2p_connect 02:40:61:c2:f3:b7 pbc
+OK
+<2>P2P-GO-NEG-SUCCESS 
+<2>P2P-GROUP-FORMATION-SUCCESS 
+<2>P2P-GROUP-STARTED sta0-p2p-0 client DIRECT-vM
+> interface
+Available interfaces:
+sta0-p2p-0
+sta0
+> p2p_group_remove sta0-p2p-0
+<2>P2P-GROUP-REMOVED sta0-p2p-0 client
+OK
+> term
+OK
+\endverbatim
+
+
+P2P device "Wireless Client2" (which ended up operating in GO role):
+
+\verbatim
+> p2p_find
+OK
+<2>P2P-DEVICE-FOUND 02:f0:bc:44:87:62 p2p_dev_addr=02:f0:bc:44:87:62
+pri_dev_type=1-0050F204-1 name='Wireless Client' config_methods=0x18c
+dev_capab=0x1 group_capab=0x0
+> p2p_connect 02:f0:bc:44:87:62 pbc
+OK
+<2>P2P-GO-NEG-SUCCESS 
+<2>P2P-GROUP-FORMATION-SUCCESS 
+<2>P2P-GROUP-STARTED sta1-p2p-0 GO DIRECT-vM
+> interface
+Available interfaces:
+sta1-p2p-0
+sta1
+> p2p_group_remove sta1-p2p-0
+<2>P2P-GROUP-REMOVED sta1-p2p-0 GO
+OK
+> term
+OK
+\endverbatim
+
+*/
diff --git a/doc/p2p_arch.dot b/doc/p2p_arch.dot
new file mode 100644 (file)
index 0000000..27ae0e2
--- /dev/null
@@ -0,0 +1,85 @@
+digraph p2p_arch {
+       ranksep=.75;
+       size = "7.5,7.5";
+
+       edge [dir=none];
+
+       subgraph cluster_wpa_gui {
+               label = "wpa_gui";
+
+               status -> Qt;
+               scan -> Qt;
+               network -> Qt;
+               Qt -> peers;
+               Qt -> WPS;
+               Qt -> gui_ctrl;
+
+               gui_ctrl [label="ctrl i/f"];
+       }
+
+       subgraph cluster_wpa_supplicant {
+               label = "wpa_supplicant"
+
+               ctrl_iface [label="ctrl i/f"];
+               authenticator [label="Authenticator"];
+               supplicant [label="Supplicant"];
+               driver_iface [label="driver i/f"];
+               p2p_module [label="P2P\nmodule"];
+               wps_registrar [label="WPS\nRegistrar"];
+               wps_enrollee [label="WPS\nEnrollee"];
+               mgmt_entity [label="Management\nentity"];
+
+               ctrl_iface -> mgmt_entity;
+               p2p_module -> mgmt_entity;
+               wps_registrar -> mgmt_entity;
+               wps_enrollee -> mgmt_entity;
+               mgmt_entity -> authenticator;
+               mgmt_entity -> supplicant;
+               mgmt_entity -> driver_iface;
+
+               { rank = same; mgmt_entity; p2p_module; }
+       }
+
+       subgraph cluster_wpa_cli {
+               label = "wpa_cli -a"
+
+               wpa_cli_action;
+       }
+
+       subgraph cluster_dnsmasq {
+               label = "dnsmasq"
+
+               dnsmasq;
+       }
+
+       subgraph cluster_dhclient {
+               label = "dhclient"
+
+               dhclient;
+       }
+
+       subgraph cluster_kernel {
+               label = "Linux kernel"
+
+               cfg80211 -> mac80211;
+               netdev -> mac80211;
+               mac80211 -> ath9k;
+       }
+
+       gui_ctrl -> ctrl_iface;
+       wpa_cli_action -> ctrl_iface;
+
+       driver_iface -> cfg80211;
+
+       wpa_cli_action -> dnsmasq;
+       wpa_cli_action -> dhclient;
+
+       dnsmasq -> netdev;
+       dhclient -> netdev;
+
+       edge [color=blue,dir=both];
+       p2p_module -> mgmt_entity -> driver_iface -> cfg80211 -> mac80211 -> ath9k;
+
+       edge [color=green,dir=both];
+       peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> p2p_module;
+}
diff --git a/doc/p2p_arch2.dot b/doc/p2p_arch2.dot
new file mode 100644 (file)
index 0000000..9c7b4b5
--- /dev/null
@@ -0,0 +1,85 @@
+digraph p2p_arch2 {
+       ranksep=.75;
+       size = "7.5,7.5";
+
+       edge [dir=none];
+
+       subgraph cluster_wpa_gui {
+               label = "wpa_gui";
+
+               status -> Qt;
+               scan -> Qt;
+               network -> Qt;
+               Qt -> peers;
+               Qt -> WPS;
+               Qt -> gui_ctrl;
+
+               gui_ctrl [label="ctrl i/f"];
+       }
+
+       subgraph cluster_wpa_supplicant {
+               label = "wpa_supplicant"
+
+               ctrl_iface [label="ctrl i/f"];
+               authenticator [label="Authenticator"];
+               supplicant [label="Supplicant"];
+               driver_iface [label="driver i/f"];
+               wps_registrar [label="WPS\nRegistrar"];
+               wps_enrollee [label="WPS\nEnrollee"];
+               mgmt_entity [label="Management\nentity"];
+
+               ctrl_iface -> mgmt_entity;
+               wps_registrar -> mgmt_entity;
+               wps_enrollee -> mgmt_entity;
+               mgmt_entity -> authenticator;
+               mgmt_entity -> supplicant;
+               mgmt_entity -> driver_iface;
+       }
+
+       subgraph cluster_wpa_cli {
+               label = "wpa_cli -a"
+
+               wpa_cli_action;
+       }
+
+       subgraph cluster_dnsmasq {
+               label = "dnsmasq"
+
+               dnsmasq;
+       }
+
+       subgraph cluster_dhclient {
+               label = "dhclient"
+
+               dhclient;
+       }
+
+       subgraph cluster_kernel {
+               label = "Kernel"
+
+               ioctl -> umac;
+               netdev -> umac;
+               umac -> p2p_module;
+               p2p_module [label="P2P\nmodule"];
+               umac -> driver;
+
+               { rank = same; umac; p2p_module; }
+       }
+
+       gui_ctrl -> ctrl_iface;
+       wpa_cli_action -> ctrl_iface;
+
+       driver_iface -> ioctl;
+
+       wpa_cli_action -> dnsmasq;
+       wpa_cli_action -> dhclient;
+
+       dnsmasq -> netdev;
+       dhclient -> netdev;
+
+       edge [color=blue,dir=both];
+       p2p_module -> umac -> driver;
+
+       edge [color=green,dir=both];
+       peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> driver_iface -> ioctl -> umac -> p2p_module;
+}
diff --git a/doc/p2p_sm.dot b/doc/p2p_sm.dot
new file mode 100644 (file)
index 0000000..640caef
--- /dev/null
@@ -0,0 +1,62 @@
+digraph p2p {
+       ranksep=.75;
+       size = "8.5,7.5";
+
+       start -> IDLE;
+       start [label="Init",shape=none];
+
+       /* Discovery: Scan followed by Find(SEARCH,LISTEN) */
+       subgraph cluster_0 {
+               label="Discovery";
+               color=lightgrey;
+               node [color=blue];
+               /* SCAN and LISTEN currently not used in the implementation */
+               SCAN [style=dotted];
+               LISTEN [style=dotted];
+
+               SCAN -> LISTEN;
+               LISTEN -> SEARCH -> LISTEN [style=dotted];
+               SEARCH -> SD_DURING_FIND [label="Peer SD capab\nand no info", weight=100];
+               SD_DURING_FIND -> SEARCH [label="RX SD Resp\nor timeout", weight=100];
+               SEARCH -> PROV_DISC_DURING_FIND [label="Prov Disc cmd\nand no Resp", weight=100];
+               PROV_DISC_DURING_FIND -> SEARCH [label="RX Prov Disc Resp\nor timeout", weight=100];
+       }
+
+       /* Group Formation */
+       subgraph cluster_1 {
+               label="Group Formation";
+               color=lightgrey;
+               node [color=green];
+
+               CONNECT -> CONNECT_LISTEN [style=dotted,weight=100];
+               CONNECT_LISTEN -> CONNECT [style=dotted,weight=100];
+               CONNECT -> WAIT_PEER_IDLE [label="RX GO Neg Resp\n(info unavail)"];
+               WAIT_PEER_IDLE -> WAIT_PEER_CONNECT [style=dotted,weight=100];
+               WAIT_PEER_CONNECT -> WAIT_PEER_IDLE [style=dotted,weight=100];
+
+               CONNECT -> GO_NEG [label="RX GO Neg Resp\n(success)", weight=10];
+               CONNECT_LISTEN -> GO_NEG [label="RX GO Neg Req or\nTX GO Neg Resp"];
+               WAIT_PEER_CONNECT -> GO_NEG [label="RX GO Neg Req"];
+               GO_NEG -> PROVISIONING [label="TX/RX GO Neg Conf"];
+       }
+
+       PROVISIONING -> IDLE [label="WPS\nsuccess"];
+
+       /* External triggers */
+       IDLE -> SCAN [label="Find cmd",weight=20];
+       IDLE -> CONNECT [label="Connect cmd",weight=20];
+       IDLE -> LISTEN_ONLY [label="Listen cmd"];
+
+       /* Timeouts */
+/*
+       edge [color=red];
+       WAIT_PEER_IDLE -> IDLE [label="timeout", weight=0];
+       WAIT_PEER_CONNECT -> IDLE [label="timeout", weight=0];
+       CONNECT -> IDLE [label="timeout", weight=0];
+       CONNECT_LISTEN -> IDLE [label="timeout", weight=0];
+       GO_NEG -> IDLE [label="timeout", weight=0];
+       PROVISIONING -> IDLE [label="timeout", weight=0];
+       LISTEN_ONLY -> IDLE [label="timeout", weight=0];
+       SEARCH -> IDLE [label="timeout", weight=0];
+*/
+}
diff --git a/eap_example/.gitignore b/eap_example/.gitignore
new file mode 100644 (file)
index 0000000..4d6d2d1
--- /dev/null
@@ -0,0 +1,4 @@
+*.d
+eap_example
+libeap.so
+libeap.a
index b897ab5..0c2921e 100644 (file)
@@ -1,12 +1,8 @@
 EAP peer/server library and example program
 Copyright (c) 2007, Jouni Malinen <j@w1.fi>
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-Alternatively, this software may be distributed under the terms of BSD
-license.
+This software may be distributed under the terms of the BSD license.
+See the parent directory README for more details.
 
 
 The interfaces of the EAP server/peer implementation are based on RFC
index b8917c8..68f3c00 100644 (file)
@@ -5,14 +5,8 @@
  * through an EAP-PEAP/MSCHAPv2 authentication.
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0b7d417..bfeafa0 100644 (file)
@@ -3,14 +3,8 @@
  * used as a library.
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 03deb67..7097bca 100644 (file)
@@ -3,14 +3,8 @@
  * a library.
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/files/wpa_supp.sh b/files/wpa_supp.sh
new file mode 100755 (executable)
index 0000000..1d3547f
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+start()
+{
+       HARDWARE_MODEL=`/bin/grep Hardware /proc/cpuinfo | /bin/awk "{print \\$3}"`
+
+       case $HARDWARE_MODEL in
+               "U1SLP" | "U1HD") /bin/echo "This is U1SLP"
+                       /usr/sbin/wpa_supplicant -u -t -B -d -Dwext -f/opt/usr/data/network/wpa_supplicant.log
+               ;;
+               "SLP7_C210")     /bin/echo "This is C210"
+                       /usr/sbin/wpa_supplicant -u -t -B -d -Dwext -f/opt/usr/data/network/wpa_supplicant.log
+               ;;
+               "SLP10_C210")   /bin/echo "This is C210"
+                       /usr/sbin/wpa_supplicant -u -t -B -d -Dwext -f/opt/usr/data/network/wpa_supplicant.log
+               ;;
+               *)
+                       /usr/sbin/wpa_supplicant -u -t -B -d -Dnl80211 -f/opt/usr/data/network/wpa_supplicant.log
+               ;;
+       esac
+}
+
+stop()
+{
+       /usr/bin/killall wpa_supplicant
+       /bin/usleep 150000
+}
+
+case $1 in
+"start")
+start
+;;
+"stop")
+stop
+;;
+*)
+/bin/echo wpa_supp.sh [start] [stop]
+exit 1
+;;
+esac
index 7f0ba5c..9837104 100644 (file)
@@ -1,3 +1,9 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
 LOCAL_PATH := $(call my-dir)
 
 WPA_BUILD_HOSTAPD := false
@@ -8,11 +14,13 @@ endif
 
 ifeq ($(WPA_BUILD_HOSTAPD),true)
 
-include $(LOCAL_PATH)/.config
+include $(LOCAL_PATH)/android.config
 
 # To ignore possible wrong network configurations
 L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
 
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
 # Set Android log name
 L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
 
@@ -31,7 +39,10 @@ INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += external/openssl/include
+# frameworks/base/cmds/keystore is the old location and can be dropped at some
+# point
 INCLUDES += frameworks/base/cmds/keystore
+INCLUDES += system/security/keystore
 ifdef CONFIG_DRIVER_NL80211
 INCLUDES += external/libnl-headers
 endif
@@ -65,6 +76,7 @@ OBJS += src/ap/utils.c
 OBJS += src/ap/authsrv.c
 OBJS += src/ap/ieee802_1x.c
 OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
 OBJS += src/ap/ieee802_11_auth.c
 OBJS += src/ap/sta_info.c
 OBJS += src/ap/wpa_auth.c
@@ -131,6 +143,7 @@ CONFIG_NO_ACCOUNTING=y
 else
 OBJS += src/radius/radius.c
 OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
 endif
 
 ifdef CONFIG_NO_ACCOUNTING
@@ -143,6 +156,12 @@ ifdef CONFIG_NO_VLAN
 L_CFLAGS += -DCONFIG_NO_VLAN
 else
 OBJS += src/ap/vlan_init.c
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_util.c
+endif
+L_CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
 endif
 
 ifdef CONFIG_NO_CTRL_IFACE
@@ -185,10 +204,26 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += src/ap/wnm_ap.c
+endif
+
 ifdef CONFIG_IEEE80211N
 L_CFLAGS += -DCONFIG_IEEE80211N
 endif
 
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
 OBJS += $(DRV_AP_OBJS)
@@ -225,6 +260,14 @@ OBJS += src/eap_server/eap_server_tls.c
 TLS_FUNCS=y
 endif
 
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
 ifdef CONFIG_EAP_PEAP
 L_CFLAGS += -DEAP_SERVER_PEAP
 OBJS += src/eap_server/eap_server_peap.c
@@ -351,25 +394,10 @@ NEED_AES_CBC=y
 NEED_MODEXP=y
 CONFIG_EAP=y
 
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 L_CFLAGS += -DCONFIG_WPS_NFC
 OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -458,6 +486,15 @@ ifndef CONFIG_TLS
 CONFIG_TLS=openssl
 endif
 
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_openssl.c
@@ -541,6 +578,9 @@ OBJS += src/tls/pkcs8.c
 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
 L_CFLAGS += -DCONFIG_TLS_INTERNAL
@@ -655,14 +695,19 @@ endif
 
 SHA1OBJS =
 ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
 SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += src/crypto/sha1-internal.c
 ifdef NEED_FIPS186_2_PRF
 SHA1OBJS += src/crypto/fips_prf_internal.c
 endif
 endif
+ifneq ($(CONFIG_TLS), openssl)
 SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += src/crypto/sha1-tprf.c
 endif
@@ -701,10 +746,17 @@ endif
 endif
 
 ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
 OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
 ifdef CONFIG_INTERNAL_SHA256
 OBJS += src/crypto/sha256-internal.c
 endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
 endif
 
 ifdef NEED_DH_GROUPS
@@ -719,11 +771,16 @@ OBJS += src/crypto/dh_group5.c
 endif
 endif
 
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
 ifdef CONFIG_NO_RANDOM_POOL
 L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
 OBJS += src/crypto/random.c
 HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
 HOBJS += $(SHA1OBJS)
 HOBJS += src/crypto/md5.c
 endif
@@ -762,11 +819,27 @@ ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 endif
 
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
 ifdef CONFIG_P2P_MANAGER
 L_CFLAGS += -DCONFIG_P2P_MANAGER
 OBJS += src/ap/p2p_hostapd.c
 endif
 
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
 OBJS += src/drivers/driver_common.c
 
 ifdef CONFIG_NO_STDOUT_DEBUG
index 47f2423..1a4e566 100644 (file)
@@ -1,5 +1,211 @@
 ChangeLog for hostapd
 
+????-??-?? - v2.1
+       * added support for simulataneous authentication of equals (SAE) for
+         stronger password-based authentication with WPA2-Personal
+
+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
index 22c09c1..843fba7 100644 (file)
@@ -8,6 +8,9 @@ endif
 
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
+CFLAGS += -fPIE
+LDFLAGS += -pie
+
 
 # Uncomment following line and set the path to your kernel tree include
 # directory if your C library does not include all header files.
@@ -43,6 +46,7 @@ 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
@@ -56,6 +60,18 @@ OBJS += ../src/ap/beacon.o
 
 OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
 
+ifdef TIZEN_EXT
+CFLAGS += -DTIZEN_EXT
+CFLAGS += -DTIZEN_EXT_SOFTAP
+CFLAGS += -DBCM_DRIVER_V115
+CFLAGS += -I../src/drivers
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+CFLAGS += -mabi=aapcs-linux
+endif
+endif
+
 NEED_RC4=y
 NEED_AES=y
 NEED_MD5=y
@@ -110,6 +126,7 @@ 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
@@ -122,6 +139,12 @@ 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
@@ -164,10 +187,26 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+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)
@@ -203,6 +242,14 @@ 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
@@ -329,25 +376,10 @@ 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
@@ -640,14 +672,19 @@ 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
@@ -687,7 +724,10 @@ 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
@@ -708,6 +748,10 @@ OBJS += ../src/crypto/dh_group5.o
 endif
 endif
 
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
 ifdef CONFIG_NO_RANDOM_POOL
 CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
@@ -752,13 +796,25 @@ 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
@@ -777,6 +833,16 @@ ifdef CONFIG_DEBUG_FILE
 CFLAGS += -DCONFIG_DEBUG_FILE
 endif
 
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+endif
+
 ALL=hostapd hostapd_cli
 
 all: verify_config $(ALL)
@@ -802,8 +868,13 @@ verify_config:
        fi
 
 install: all
+ifdef TIZEN_EXT
+       mkdir -p $(DESTDIR)/usr/sbin
+       for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/sbin/$$i; done
+else
        mkdir -p $(DESTDIR)/usr/local/bin
        for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+endif
 
 ../src/drivers/build.hostapd:
        @if [ -f ../src/drivers/build.wpa_supplicant ]; then \
index a211cdd..39b70ca 100644 (file)
@@ -2,37 +2,22 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
          Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2013, Jouni Malinen <j@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 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
 -------
 
-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:
+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
index 17988d4..654b5bc 100644 (file)
@@ -66,6 +66,10 @@ 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:
@@ -289,3 +293,62 @@ For example:
 
 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.
+
+"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_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/hostapd/android.config b/hostapd/android.config
new file mode 100644 (file)
index 0000000..51d6656
--- /dev/null
@@ -0,0 +1,190 @@
+# 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
+CONFIG_LIBNL20=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-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
+
+# 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
+
+# Add support for writing debug log to Android logcat instead of standard output
+CONFIG_ANDROID_LOG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Remove support for dumping 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
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# Enable AP
+CONFIG_AP=y
index ca79695..9cc45e9 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -89,7 +83,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
                        return -1;
                }
 
-               vlan = os_malloc(sizeof(*vlan));
+               vlan = os_zalloc(sizeof(*vlan));
                if (vlan == NULL) {
                        wpa_printf(MSG_ERROR, "Out of memory while reading "
                                   "VLAN interfaces from '%s'", fname);
@@ -97,7 +91,6 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
                        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)
@@ -173,7 +166,7 @@ static int hostapd_config_read_maclist(const char *fname,
                if (*pos != '\0')
                        vlan_id = atoi(pos);
 
-               newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+               newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
                if (newacl == NULL) {
                        wpa_printf(MSG_ERROR, "MAC list reallocation failed");
                        fclose(f);
@@ -206,6 +199,12 @@ static int hostapd_config_read_eap_user(const char *fname,
        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);
@@ -481,7 +480,7 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
        int ret;
        static int server_index = 1;
 
-       nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+       nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
        if (nserv == NULL)
                return -1;
 
@@ -497,6 +496,100 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
 
        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 */
 
 
@@ -536,6 +629,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
                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);
@@ -561,47 +660,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
 
 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)
+       int val = wpa_parse_cipher(value);
+       if (val < 0) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+                          line, value);
                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);
@@ -646,14 +710,14 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
 }
 
 
-static int hostapd_parse_rates(int **rate_list, char *val)
+static int hostapd_parse_intlist(int **int_list, char *val)
 {
        int *list;
        int count;
        char *pos, *end;
 
-       os_free(*rate_list);
-       *rate_list = NULL;
+       os_free(*int_list);
+       *int_list = NULL;
 
        pos = val;
        count = 0;
@@ -680,7 +744,7 @@ static int hostapd_parse_rates(int **rate_list, char *val)
        }
        list[count] = -1;
 
-       *rate_list = list;
+       *int_list = list;
        return 0;
 }
 
@@ -692,8 +756,8 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
        if (*ifname == '\0')
                return -1;
 
-       bss = os_realloc(conf->bss, (conf->num_bss + 1) *
-                        sizeof(struct hostapd_bss_config));
+       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");
@@ -817,78 +881,6 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
 }
 
 
-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)
 {
@@ -1040,6 +1032,71 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
 #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)
 {
@@ -1096,6 +1153,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 #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;
@@ -1105,10 +1168,10 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 
        if (conf->ieee80211n && bss->wpa &&
            !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
-           !(bss->rsn_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 to be enabled, disabling HT "
+                          "requires CCMP/GCMP to be enabled, disabling HT "
                           "capabilities");
        }
 #endif /* CONFIG_IEEE80211N */
@@ -1125,8 +1188,27 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
                           "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;
 }
 
@@ -1141,6 +1223,12 @@ static int hostapd_config_check(struct hostapd_config *conf)
                return -1;
        }
 
+       if (conf->ieee80211h && !conf->ieee80211d) {
+               wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+                          "IEEE 802.11d enabled");
+               return -1;
+       }
+
        for (i = 0; i < conf->num_bss; i++) {
                if (hostapd_config_check_bss(&conf->bss[i], conf))
                        return -1;
@@ -1167,9 +1255,9 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
        }
        len /= 2;
 
-       rc = os_realloc(bss->roaming_consortium,
-                       sizeof(struct hostapd_roaming_consortium) *
-                       (bss->roaming_consortium_count + 1));
+       rc = os_realloc_array(bss->roaming_consortium,
+                             bss->roaming_consortium_count + 1,
+                             sizeof(struct hostapd_roaming_consortium));
        if (rc == NULL)
                return -1;
 
@@ -1181,81 +1269,429 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
 
        return 0;
 }
-#endif /* CONFIG_INTERWORKING */
 
 
-/**
- * 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)
+static int parse_lang_string(struct hostapd_lang_string **array,
+                            unsigned int *count, char *pos)
 {
-       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;
+       char *sep;
+       size_t clen, nlen;
+       struct hostapd_lang_string *ls;
 
-       f = fopen(fname, "r");
-       if (f == NULL) {
-               wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
-                          "for reading.", fname);
-               return NULL;
+       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;
+}
 
-       conf = hostapd_config_defaults();
-       if (conf == NULL) {
-               fclose(f);
-               return NULL;
+
+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;
 
-       /* 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;
+       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');
        }
 
-       bss = conf->last_bss = conf->bss;
+       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);
 
-       while (fgets(buf, sizeof(buf), f)) {
-               bss = conf->last_bss;
-               line++;
+       return 0;
 
-               if (buf[0] == '#')
-                       continue;
-               pos = buf;
-               while (*pos != '\0') {
-                       if (*pos == '\n') {
-                               *pos = '\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 (buf[0] == '\0')
-                       continue;
 
-               pos = os_strchr(buf, '=');
-               if (pos == NULL) {
-                       wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
-                                  line, buf);
-                       errors++;
-                       continue;
+               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;
                }
-               *pos = '\0';
-               pos++;
+               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, "vlan_bridge") == 0) {
+                       os_strlcpy(bss->vlan_bridge, pos,
+                                  sizeof(bss->vlan_bridge));
                } else if (os_strcmp(buf, "wds_bridge") == 0) {
                        os_strlcpy(bss->wds_bridge, pos,
                                   sizeof(bss->wds_bridge));
@@ -1299,9 +1735,24 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        } 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, "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 &&
@@ -1334,12 +1785,16 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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, "ieee80211h") == 0) {
+                       conf->ieee80211h = atoi(pos);
                } else if (os_strcmp(buf, "ieee8021x") == 0) {
                        bss->ieee802_1x = atoi(pos);
                } else if (os_strcmp(buf, "eapol_version") == 0) {
@@ -1378,6 +1833,9 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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, "ocsp_stapling_response") == 0) {
+                       os_free(bss->ocsp_stapling_response);
+                       bss->ocsp_stapling_response = os_strdup(pos);
                } else if (os_strcmp(buf, "dh_file") == 0) {
                        os_free(bss->dh_file);
                        bss->dh_file = os_strdup(pos);
@@ -1450,7 +1908,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                           "allocate memory for "
                                           "eap_req_id_text", line);
                                errors++;
-                               continue;
+                               return errors;
                        }
                        bss->eap_req_id_text_len =
                                os_strlen(bss->eap_req_id_text);
@@ -1570,6 +2028,51 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } 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);
@@ -1609,6 +2112,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        } 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);
@@ -1624,6 +2129,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                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);
@@ -1694,7 +2201,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "mobility_domain '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "r1_key_holder") == 0) {
                        if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
@@ -1703,7 +2210,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "r1_key_holder '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
                        bss->r0_key_lifetime = atoi(pos);
@@ -1714,14 +2221,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "r0kh '%s'", line, pos);
                                errors++;
-                               continue;
+                               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++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
                        bss->pmk_r1_push = atoi(pos);
@@ -1745,7 +2252,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
                                           " (from group name '%s')",
                                           bss->ctrl_interface_gid, group);
-                               continue;
+                               return errors;
                        }
 
                        /* Group name not found - try to parse this as gid */
@@ -1754,7 +2261,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
                                           "'%s'", line, group);
                                errors++;
-                               continue;
+                               return errors;
                        }
                        bss->ctrl_interface_gid_set = 1;
                        wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
@@ -1782,6 +2289,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                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);
@@ -1853,13 +2362,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        } else
                                conf->send_probe_response = val;
                } else if (os_strcmp(buf, "supported_rates") == 0) {
-                       if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+                       if (hostapd_parse_intlist(&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)) {
+                       if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
                                wpa_printf(MSG_ERROR, "Line %d: invalid rate "
                                           "list", line);
                                errors++;
@@ -1898,6 +2408,15 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                           "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);
@@ -1920,7 +2439,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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)) {
+                       if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+                                                 pos)) {
                                wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
                                           "ac item", line);
                                errors++;
@@ -1969,6 +2489,26 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } 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) {
@@ -1983,6 +2523,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                           "wps_state", line);
                                errors++;
                        }
+               } else if (os_strcmp(buf, "wps_independent") == 0) {
+                       bss->wps_independent = atoi(pos);
                } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
                        bss->ap_setup_locked = atoi(pos);
                } else if (os_strcmp(buf, "uuid") == 0) {
@@ -2092,6 +2634,29 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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++;
+                       }
+                       bss->wps_nfc_pw_from_config = 1;
+               } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_pubkey);
+                       bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+                       bss->wps_nfc_pw_from_config = 1;
+               } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_privkey);
+                       bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+                       bss->wps_nfc_pw_from_config = 1;
+               } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+                       wpabuf_free(bss->wps_nfc_dev_pw);
+                       bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+                       bss->wps_nfc_pw_from_config = 1;
+#endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P_MANAGER
                } else if (os_strcmp(buf, "manage_p2p") == 0) {
@@ -2133,12 +2698,18 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: invalid "
                                           "time_zone", line);
                                errors++;
-                               continue;
+                               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);
@@ -2173,12 +2744,208 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } 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 */
+#ifdef CONFIG_TESTING_OPTIONS
+#define PARSE_TEST_PROBABILITY(_val)                                   \
+               } else if (os_strcmp(buf, #_val) == 0) {                \
+                       char *end;                                      \
+                                                                       \
+                       conf->_val = strtod(pos, &end);                 \
+                       if (*end || conf->_val < 0.0d ||                \
+                           conf->_val > 1.0d) {                        \
+                               wpa_printf(MSG_ERROR,                   \
+                                          "Line %d: Invalid value '%s'", \
+                                          line, pos);                  \
+                               errors++;                               \
+                               return errors;                          \
+                       }
+               PARSE_TEST_PROBABILITY(ignore_probe_probability)
+               PARSE_TEST_PROBABILITY(ignore_auth_probability)
+               PARSE_TEST_PROBABILITY(ignore_assoc_probability)
+               PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
+               PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+#endif /* CONFIG_TESTING_OPTIONS */
+               } else if (os_strcmp(buf, "vendor_elements") == 0) {
+                       struct wpabuf *elems;
+                       size_t len = os_strlen(pos);
+                       if (len & 0x01) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "vendor_elements '%s'", line, pos);
+                               return 1;
+                       }
+                       len /= 2;
+                       if (len == 0) {
+                               wpabuf_free(bss->vendor_elements);
+                               bss->vendor_elements = NULL;
+                               return 0;
+                       }
+
+                       elems = wpabuf_alloc(len);
+                       if (elems == NULL)
+                               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 if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
+                       bss->sae_anti_clogging_threshold = atoi(pos);
+               } else if (os_strcmp(buf, "sae_groups") == 0) {
+                       if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "sae_groups value '%s'", line, pos);
+                               return 1;
+                       }
                } else {
                        wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
                                   "item '%s'", line, buf);
@@ -2186,65 +2953,130 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                }
        }
 
-       fclose(f);
+       return errors;
+}
 
-       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;
-               }
+static void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+       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;
+       }
+
+       if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+               bss->rsn_pairwise = bss->wpa_pairwise;
+       bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+                                                   bss->rsn_pairwise);
+
+       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++;
 
-               /* 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 (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
                }
-               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) {
-                       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;
+               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++;
 
@@ -2259,3 +3091,28 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 
        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;
+}
index 7111a9a..fba57b8 100644 (file)
@@ -2,19 +2,16 @@
  * hostapd / Configuration file parser
  * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 */
index a38d77c..021cbe5 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
+#include "config_file.h"
 #include "ctrl_iface.h"
 
 
@@ -158,173 +154,6 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
 }
 
 
-#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 */
-
-
-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_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;
-}
-
-
-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_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;
-}
-
-
 #ifdef CONFIG_IEEE80211W
 #ifdef NEED_AP_MLME
 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
@@ -422,28 +251,162 @@ static int hostapd_ctrl_iface_wps_check_pin(
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
+#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)
 {
-       char *path, *method, *name;
+       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;
+}
 
-       path = os_strchr(txt, ' ');
-       if (path == NULL)
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+                                                  char *cmd, char *reply,
+                                                  size_t max_len)
+{
+       struct wpabuf *buf;
+       int res;
+       char *pos;
+       int ndef;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
                return -1;
-       *path++ = '\0';
+       *pos++ = '\0';
 
-       method = os_strchr(path, ' ');
-       if (method == NULL)
+       if (os_strcmp(cmd, "WPS") == 0)
+               ndef = 0;
+       else if (os_strcmp(cmd, "NDEF") == 0)
+               ndef = 1;
+       else
                return -1;
-       *method++ = '\0';
 
-       name = os_strchr(method, ' ');
-       if (name != NULL)
-               *name++ = '\0';
+       if (os_strcmp(pos, "WPS-CR") == 0)
+               buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+       else
+               buf = NULL;
+       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 hostapd_wps_start_oob(hapd, txt, path, method, name);
+       return res;
 }
-#endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
+                                                 char *cmd)
+{
+       /*
+        * Since NFC connection handover provided full WPS Credential, there is
+        * no need for additional operations within hostapd. Just report this in
+        * debug log.
+        */
+       wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
+       return 0;
+}
+
+#endif /* CONFIG_WPS_NFC */
 
 
 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
@@ -527,19 +490,73 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
 #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;
+       const char *url, *timerstr;
        u8 buf[1000], *pos;
        struct ieee80211_mgmt *mgmt;
        size_t url_len;
+       int disassoc_timer;
 
        if (hwaddr_aton(cmd, addr))
                return -1;
-       url = cmd + 17;
-       if (*url != ' ')
+
+       timerstr = cmd + 17;
+       if (*timerstr != ' ')
+               return -1;
+       timerstr++;
+       disassoc_timer = atoi(timerstr);
+       if (disassoc_timer < 0 || disassoc_timer > 65535)
+               return -1;
+
+       url = os_strchr(timerstr, ' ');
+       if (url == NULL)
                return -1;
        url++;
        url_len = os_strlen(url);
@@ -558,8 +575,9 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
        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;
+       mgmt->u.action.u.bss_tm_req.disassoc_timer =
+               host_to_le16(disassoc_timer);
+       mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
 
        pos = mgmt->u.action.u.bss_tm_req.variable;
 
@@ -574,9 +592,46 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
                return -1;
        }
 
+       /* send disassociation frame after time-out */
+       if (disassoc_timer) {
+               struct sta_info *sta;
+               int timeout, beacon_int;
+
+               /*
+                * Prevent STA from reconnecting using cached PMKSA to force
+                * full authentication with the authentication server (which may
+                * decide to reject the connection),
+                */
+               wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
+
+               sta = ap_get_sta(hapd, addr);
+               if (sta == NULL) {
+                       wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+                                  "for ESS disassociation imminent message",
+                                  MAC2STR(addr));
+                       return -1;
+               }
+
+               beacon_int = hapd->iconf->beacon_int;
+               if (beacon_int < 1)
+                       beacon_int = 100; /* best guess */
+               /* Calculate timeout in ms based on beacon_int in TU */
+               timeout = disassoc_timer * beacon_int * 128 / 125;
+               wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+                          " set to %d ms", MAC2STR(addr), timeout);
+
+               sta->timeout_next = STA_DISASSOC_FROM_CLI;
+               eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+               eloop_register_timeout(timeout / 1000,
+                                      timeout % 1000 * 1000,
+                                      ap_handle_timer, hapd, sta);
+       }
+
        return 0;
 }
 
+#endif /* CONFIG_WNM */
+
 
 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                                         char *buf, size_t buflen)
@@ -590,7 +645,8 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
        ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
                          "ssid=%s\n",
                          MAC2STR(hapd->own_addr),
-                         hapd->conf->ssid.ssid);
+                         wpa_ssid_txt(hapd->conf->ssid.ssid,
+                                      hapd->conf->ssid.ssid_len));
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
@@ -679,14 +735,9 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                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_TKIP) {
-               ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+       if (hapd->conf->wpa) {
+               ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
+                                 wpa_cipher_txt(hapd->conf->wpa_group));
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
                pos += ret;
@@ -698,18 +749,11 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                        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_TKIP) {
-                       ret = os_snprintf(pos, end - pos, "TKIP ");
-                       if (ret < 0 || ret >= end - pos)
-                               return pos - buf;
-                       pos += ret;
-               }
+               ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+                                       " ");
+               if (ret < 0)
+                       return pos - buf;
+               pos += ret;
 
                ret = os_snprintf(pos, end - pos, "\n");
                if (ret < 0 || ret >= end - pos)
@@ -723,18 +767,11 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                        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_TKIP) {
-                       ret = os_snprintf(pos, end - pos, "TKIP ");
-                       if (ret < 0 || ret >= end - pos)
-                               return pos - buf;
-                       pos += ret;
-               }
+               ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+                                       " ");
+               if (ret < 0)
+                       return pos - buf;
+               pos += ret;
 
                ret = os_snprintf(pos, end - pos, "\n");
                if (ret < 0 || ret >= end - pos)
@@ -779,8 +816,16 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
                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 = -1;
+               ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
        }
 
        return ret;
@@ -805,6 +850,36 @@ static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
 }
 
 
+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)
 {
@@ -919,21 +994,41 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strcmp(buf, "WPS_PBC") == 0) {
                if (hostapd_wps_button_pushed(hapd, NULL))
                        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))
+       } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+               if (hostapd_wps_cancel(hapd))
                        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);
        } 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);
+       } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+               reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+                       hapd, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+               if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+                       reply_len = -1;
+#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);
@@ -943,6 +1038,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } 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;
@@ -978,7 +1082,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
 }
 
 
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
                                      const char *txt, size_t len)
 {
        struct hostapd_data *hapd = ctx;
@@ -994,7 +1098,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        int s = -1;
        char *fname = NULL;
 
-       hapd->ctrl_sock = -1;
+       if (hapd->ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
 
        if (hapd->conf->ctrl_interface == NULL)
                return 0;
@@ -1010,12 +1117,35 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        }
 
        if (hapd->conf->ctrl_interface_gid_set &&
-           chown(hapd->conf->ctrl_interface, 0,
+           chown(hapd->conf->ctrl_interface, -1,
                  hapd->conf->ctrl_interface_gid) < 0) {
                perror("chown[ctrl_interface]");
                return -1;
        }
 
+       if (!hapd->conf->ctrl_interface_gid_set &&
+           hapd->iface->interfaces->ctrl_iface_group &&
+           chown(hapd->conf->ctrl_interface, -1,
+                 hapd->iface->interfaces->ctrl_iface_group) < 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;
@@ -1051,7 +1181,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
                        }
                        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
                            0) {
-                               perror("bind(PF_UNIX)");
+                               perror("hostapd-ctrl-iface: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1068,7 +1198,14 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        }
 
        if (hapd->conf->ctrl_interface_gid_set &&
-           chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+           chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+               perror("chown[ctrl_interface/ifname]");
+               goto fail;
+       }
+
+       if (!hapd->conf->ctrl_interface_gid_set &&
+           hapd->iface->interfaces->ctrl_iface_group &&
+           chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
                perror("chown[ctrl_interface/ifname]");
                goto fail;
        }
@@ -1133,6 +1270,231 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
 }
 
 
+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;
+               }
+       } else if (interface->ctrl_iface_group &&
+                  chown(interface->global_iface_path, -1,
+                        interface->ctrl_iface_group) < 0) {
+               perror("chown[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 (interface->ctrl_iface_group &&
+           chown(fname, -1, interface->ctrl_iface_group) < 0) {
+               perror("chown[ctrl_interface]");
+               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)
 {
index c997141..3341a66 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / UNIX domain socket -based control interface
  * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_H
@@ -18,6 +12,8 @@
 #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)
 {
@@ -27,6 +23,17 @@ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
 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 */
index bae5ba2..317fe74 100644 (file)
@@ -84,6 +84,9 @@ CONFIG_EAP_TTLS=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
 
@@ -105,6 +108,8 @@ CONFIG_EAP_TTLS=y
 #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
@@ -133,6 +138,13 @@ CONFIG_IPV6=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.
@@ -155,6 +167,10 @@ CONFIG_IPV6=y
 # 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.
@@ -245,3 +261,17 @@ CONFIG_IPV6=y
 # 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
+
+# Testing options
+# This can be used to enable some testing options (see also the example
+# configuration file) that are really useful only for testing clients that
+# connect to this hostapd. These options allow, for example, to drop a
+# certain percentage of probe requests or auth/(re)assoc frames.
+#
+#CONFIG_TESTING_OPTIONS=y
index 110cedc..fcd9890 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / State dump
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -25,6 +19,7 @@
 #include "ap/ap_config.h"
 #include "ap/sta_info.h"
 #include "dump_state.h"
+#include "ap/ap_drv_ops.h"
 
 
 static void fprint_char(FILE *f, char c)
@@ -78,6 +73,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
 #ifndef CONFIG_NO_RADIUS
        char *buf;
 #endif /* CONFIG_NO_RADIUS */
+       struct hostap_sta_driver_data data;
 
        if (!hapd->conf->dump_log_name) {
                wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
@@ -145,6 +141,13 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
                          "DEAUTH")));
 
                ieee802_1x_dump_state(f, "  ", sta);
+
+               if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) == 0) {
+                       fprintf(f, "  rx_pkt=%lu tx_pkt=%lu\n"
+                               "  rx_byte=%lu tx_byte=%lu\n",
+                               data.rx_packets, data.tx_packets,
+                               data.rx_bytes, data.tx_bytes);
+               }
        }
 
 #ifndef CONFIG_NO_RADIUS
index e14f08a..a209d65 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / State dump
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DUMP_STATE_H
index bab2871..0a7ff91 100644 (file)
@@ -2,14 +2,8 @@
  * EAP method registration
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -45,6 +39,11 @@ int eap_server_register_methods(void)
                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();
index 82e7171..c342351 100644 (file)
@@ -2,14 +2,8 @@
  * EAP method registration
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_REGISTER_H
index 2919122..e04e2e9 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
  * 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.
+ * 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"
 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 {
@@ -73,6 +78,7 @@ struct milenage_parameters {
        u8 opc[16];
        u8 amf[2];
        u8 sqn[6];
+       int set;
 };
 
 static struct milenage_parameters *milenage_db = NULL;
@@ -87,6 +93,144 @@ static struct milenage_parameters *milenage_db = NULL;
 #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;
@@ -102,7 +246,7 @@ static int open_socket(const char *path)
        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)");
+               perror("hlr-auc-gw: bind(PF_UNIX)");
                close(s);
                return -1;
        }
@@ -216,7 +360,7 @@ static int read_gsm_triplets(const char *fname)
                gsm_db = g;
                g = NULL;
        }
-       free(g);
+       os_free(g);
 
        fclose(f);
 
@@ -366,7 +510,7 @@ static int read_milenage(const char *fname)
                milenage_db = m;
                m = NULL;
        }
-       free(m);
+       os_free(m);
 
        fclose(f);
 
@@ -374,6 +518,80 @@ static int read_milenage(const char *fname)
 }
 
 
+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;
@@ -384,6 +602,11 @@ static struct milenage_parameters * get_milenage(const char *imsi)
                m = m->next;
        }
 
+#ifdef CONFIG_SQLITE
+       if (!m)
+               m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
        return m;
 }
 
@@ -466,6 +689,28 @@ 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)
 {
@@ -479,13 +724,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
        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_byte_array(m->sqn, 6);
+               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]);
@@ -502,7 +752,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
                memset(res, '2', EAP_AKA_RES_MAX_LEN);
                res_len = EAP_AKA_RES_MAX_LEN;
 #else /* AKA_USE_FIXED_TEST_VALUES */
-               return;
+               failed = 1;
 #endif /* AKA_USE_FIXED_TEST_VALUES */
        }
 
@@ -512,6 +762,13 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
        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);
@@ -522,6 +779,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
        *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,
@@ -569,6 +827,10 @@ static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
                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;
        }
 }
 
@@ -615,22 +877,32 @@ 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;
-               free(gprev);
+               os_free(gprev);
        }
 
        m = milenage_db;
        while (m) {
                prev = m;
                m = m->next;
-               free(prev);
+               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 */
 }
 
 
@@ -645,18 +917,22 @@ static void usage(void)
 {
        printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
               "database/authenticator\n"
-              "Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
+              "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
               "\n"
               "usage:\n"
-              "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
-              "[-m<milenage file>]\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",
+              "  -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);
 }
 
@@ -664,34 +940,65 @@ static void usage(void)
 int main(int argc, char *argv[])
 {
        int c;
-       char *milenage_file = NULL;
        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, "g:hm:s:");
+               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;
 
@@ -711,5 +1018,14 @@ int main(int argc, char *argv[])
        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;
 }
diff --git a/hostapd/hlr_auc_gw.txt b/hostapd/hlr_auc_gw.txt
new file mode 100644 (file)
index 0000000..097bbce
--- /dev/null
@@ -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'
index 5272d58..de10c4e 100644 (file)
@@ -84,6 +84,14 @@ ctrl_interface_group=0
 
 # 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.
@@ -97,7 +105,15 @@ ssid=test
 # (default: 0 = disabled)
 #ieee80211d=1
 
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=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
 
@@ -196,6 +212,13 @@ auth_algs=3
 #     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
@@ -339,6 +362,12 @@ wmm_ac_vo_acm=0
 # 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
@@ -410,6 +439,157 @@ wmm_ac_vo_acm=0
 # 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
@@ -466,6 +646,8 @@ eapol_key_index_workaround=0
 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
@@ -495,6 +677,20 @@ eap_server=0
 # 2 = check all CRLs in the certificate path
 #check_crl=1
 
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+#      -no_nonce \
+#      -CAfile /etc/hostapd.ca.pem \
+#      -issuer /etc/hostapd.ca.pem \
+#      -cert /etc/hostapd.server.pem \
+#      -url http://ocsp.example.com:8888/ \
+#      -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
 # dh_file: File path to DH/DSA parameters file (in PEM format)
 # This is an optional configuration file for setting parameters for an
 # ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -518,8 +714,10 @@ eap_server=0
 # 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.
+# 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
@@ -626,13 +824,18 @@ own_ip_addr=127.0.0.1
 # 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.
+# VLANID as a string). 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
@@ -644,6 +847,8 @@ own_ip_addr=127.0.0.1
 # 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).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
 #vlan_file=/etc/hostapd.vlan
 
 # Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -653,6 +858,67 @@ own_ip_addr=127.0.0.1
 # to the bridge.
 #vlan_tagged_interface=eth0
 
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
+# 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 ##############################
 
@@ -798,6 +1064,19 @@ own_ip_addr=127.0.0.1
 # 1 = enabled
 #okc=1
 
+# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
+# This parameter defines how many open SAE instances can be in progress at the
+# same time before the anti-clogging mechanism is taken into use.
+#sae_anti_clogging_threshold=5
+
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). All groups that are supported by the
+# implementation are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=19 20 21 25 26
 
 ##### IEEE 802.11r configuration ##############################################
 
@@ -872,6 +1151,14 @@ own_ip_addr=127.0.0.1
 # 2 = WPS enabled, configured
 #wps_state=2
 
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
 # 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.
@@ -1027,6 +1314,18 @@ own_ip_addr=127.0.0.1
 # 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
@@ -1054,6 +1353,16 @@ own_ip_addr=127.0.0.1
 # 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
@@ -1107,11 +1416,160 @@ own_ip_addr=127.0.0.1
 # 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 a
+# 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
+
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+
 ##### Multiple BSSID support ##################################################
 #
 # Above configuration is using the default interface (wlan#, or multi-SSID VLAN
index ac9a5d8..12a2c61 100644 (file)
@@ -69,6 +69,9 @@
 "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
@@ -89,3 +92,6 @@
 "3"*           SIM     [2]
 "4"*           AKA     [2]
 "5"*           SIM     [2]
+"6"*           AKA'    [2]
+"7"*           AKA'    [2]
+"8"*           AKA'    [2]
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
new file mode 100644 (file)
index 0000000..f688327
--- /dev/null
@@ -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');
index 527860c..661f709 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 
 static const char *hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2013, Jouni Malinen <j@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";
+"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 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"
+"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"
@@ -94,9 +71,12 @@ static const char *commands_help =
 "   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"
-#ifdef CONFIG_WPS_OOB
-"   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
-#endif /* CONFIG_WPS_OOB */
+"   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 */
@@ -415,38 +395,105 @@ static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
-                                  char *argv[])
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
 {
-       char cmd[256];
+       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 != 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");
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_config_token' command - one argument "
+                      "is required.\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]);
+       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_OOB command.\n");
+               printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
                return -1;
        }
        return wpa_ctrl_command(ctrl, cmd);
 }
-#endif /* CONFIG_WPS_OOB */
+
+
+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);
+}
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+                                               int argc, char *argv[])
+{
+       char cmd[64];
+       int res;
+
+       if (argc != 2) {
+               printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+                      "are required.\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long NFC_GET_HANDOVER_SEL 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,
@@ -515,19 +562,19 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
 #endif /* CONFIG_WPS */
 
 
-static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
-                                       char *argv[])
+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 'ess_disassoc' command - two arguments (STA "
-                      "addr and URL) are needed\n");
+               printf("Invalid 'disassoc_imminent' command - two arguments "
+                      "(STA addr and Disassociation Timer) are needed\n");
                return -1;
        }
 
-       res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+       res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
                          argv[0], argv[1]);
        if (res < 0 || res >= (int) sizeof(buf))
                return -1;
@@ -535,6 +582,26 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char buf[300];
+       int res;
+
+       if (argc < 3) {
+               printf("Invalid 'ess_disassoc' command - three arguments (STA "
+                      "addr, disassoc timer, and URL) are needed\n");
+               return -1;
+       }
+
+       res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
+                         argv[0], argv[1], argv[2]);
+       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[])
 {
@@ -742,12 +809,17 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "wps_pin", hostapd_cli_cmd_wps_pin },
        { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
        { "wps_pbc", hostapd_cli_cmd_wps_pbc },
-#ifdef CONFIG_WPS_OOB
-       { "wps_oob", hostapd_cli_cmd_wps_oob },
-#endif /* CONFIG_WPS_OOB */
+       { "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 },
+       { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
+#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 },
@@ -911,7 +983,7 @@ static void hostapd_cli_interactive(void)
 
        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, NULL, NULL, NULL);
        eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
 
        eloop_run();
index da8135b..90e5966 100644 (file)
@@ -2,19 +2,14 @@
  * hostapd / main()
  * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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>
+#include <grp.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "utils/common.h"
@@ -27,6 +22,7 @@
 #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"
@@ -48,29 +44,6 @@ struct hapd_global {
 static struct hapd_global global;
 
 
-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)
@@ -194,14 +167,9 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
        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)
@@ -209,7 +177,7 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
        hapd_iface->conf = conf;
 
        hapd_iface->num_bss = conf->num_bss;
-       hapd_iface->bss = os_zalloc(conf->num_bss *
+       hapd_iface->bss = os_calloc(conf->num_bss,
                                    sizeof(struct hostapd_data *));
        if (hapd_iface->bss == NULL)
                goto fail;
@@ -226,6 +194,8 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
        return hapd_iface;
 
 fail:
+       wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+                  config_file);
        if (conf)
                hostapd_config_free(conf);
        if (hapd_iface) {
@@ -276,13 +246,13 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
        }
        params.bssid = b;
        params.ifname = hapd->conf->iface;
-       params.ssid = (const u8 *) hapd->conf->ssid.ssid;
+       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_zalloc(hapd->iface->num_bss * sizeof(char *));
+       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++) {
@@ -306,27 +276,16 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
            hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
                iface->drv_flags = capa.flags;
                iface->probe_resp_offloads = capa.probe_resp_offloads;
+               iface->extended_capa = capa.extended_capa;
+               iface->extended_capa_mask = capa.extended_capa_mask;
+               iface->extended_capa_len = capa.extended_capa_len;
+               iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
        }
 
        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)
@@ -345,6 +304,14 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
                        iface->bss[0]->conf->logger_stdout_level--;
        }
 
+       if (iface->conf->bss[0].iface[0] == '\0' &&
+           !hostapd_drv_none(iface->bss[0])) {
+               wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+                          config_fname);
+               hostapd_interface_deinit_free(iface);
+               return NULL;
+       }
+
        if (hostapd_driver_init(iface) ||
            hostapd_setup_interface(iface)) {
                hostapd_interface_deinit_free(iface);
@@ -436,7 +403,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
                wpa_printf(MSG_ERROR, "No drivers enabled");
                return -1;
        }
-       global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+       global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
        if (global.drv_priv == NULL)
                return -1;
 
@@ -513,7 +480,7 @@ static void show_version(void)
                "hostapd v" VERSION_STR "\n"
                "User space daemon for IEEE 802.11 AP management,\n"
                "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-               "Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> "
+               "Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> "
                "and contributors\n");
 }
 
@@ -524,13 +491,17 @@ static void usage(void)
        fprintf(stderr,
                "\n"
                "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
-               "<configuration file(s)>\n"
+               "\\\n"
+               "         [-g <global ctrl_iface>] [-G <group>] \\\n"
+               "         <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"
+               "   -G   group for control interfaces\n"
                "   -P   PID file\n"
                "   -K   include key data in debug messages\n"
 #ifdef CONFIG_DEBUG_FILE
@@ -552,6 +523,46 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
 }
 
 
+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) {
+               wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+                          "file");
+               os_free(interfaces->global_iface_path);
+               interfaces->global_iface_path = NULL;
+               return -1;
+       }
+
+       *pos = '\0';
+       interfaces->global_iface_name = pos + 1;
+
+       return 0;
+}
+
+
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+                                       const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+       struct group *grp;
+       grp = getgrnam(group);
+       if (grp == NULL) {
+               wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+               return -1;
+       }
+       interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+       return 0;
+}
+
+
 int main(int argc, char *argv[])
 {
        struct hapd_interfaces interfaces;
@@ -565,8 +576,19 @@ int main(int argc, char *argv[])
        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:tv");
+               c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
                if (c < 0)
                        break;
                switch (c) {
@@ -601,14 +623,21 @@ int main(int argc, char *argv[])
                        show_version();
                        exit(1);
                        break;
-
+               case 'g':
+                       if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+                               return -1;
+                       break;
+               case 'G':
+                       if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+                               return -1;
+                       break;
                default:
                        usage();
                        break;
                }
        }
 
-       if (optind == argc)
+       if (optind == argc && interfaces.global_iface_path == NULL)
                usage();
 
        wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
@@ -617,31 +646,42 @@ int main(int argc, char *argv[])
                wpa_debug_open_file(log_file);
 
        interfaces.count = argc - optind;
-       interfaces.iface = os_zalloc(interfaces.count *
-                                    sizeof(struct hostapd_iface *));
-       if (interfaces.iface == NULL) {
-               wpa_printf(MSG_ERROR, "malloc failed");
-               return -1;
+       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))
+       if (hostapd_global_init(&interfaces, entropy_file)) {
+               wpa_printf(MSG_ERROR, "Failed to initilize global context");
                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])
+               if (!interfaces.iface[i]) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize interface");
                        goto out;
+               }
        }
 
-       if (hostapd_global_run(&interfaces, daemonize, pid_file))
+       hostapd_global_ctrl_iface_init(&interfaces);
+
+       if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+               wpa_printf(MSG_ERROR, "Failed to start eloop");
                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]);
index 839802a..7064b9c 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - Plaintext password to NtPasswordHash
  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
new file mode 100755 (executable)
index 0000000..61b5519
--- /dev/null
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@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 logging
+logging.basicConfig()
+
+import wpaspy
+
+wpas_ctrl = '/var/run/hostapd'
+
+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 hostapd: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No hostapd control interface found"
+        return None
+
+    for ctrl in ifaces:
+        try:
+            wpas = wpaspy.Ctrl(ctrl)
+            return wpas
+        except Exception, e:
+            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_config_token():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+                        str(req).encode("hex") + " " +
+                        str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+    def __init__(self):
+        super(HandoverServer, self).__init__()
+
+    def process_request(self, request):
+        print "HandoverServer - request received"
+        print "Parsed handover request: " + request.pretty()
+
+        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+        for carrier in request.carriers:
+            print "Remote carrier type: " + carrier.type
+            if carrier.type == "application/vnd.wfa.wsc":
+                print "WPS carrier type match - add WPS carrier record"
+                self.received_carrier = carrier.record
+                data = wpas_get_handover_sel()
+                if data is None:
+                    print "Could not get handover select carrier record from hostapd"
+                    continue
+                print "Handover select carrier record from hostapd:"
+                print data.encode("hex")
+                self.sent_carrier = data
+
+                message = nfc.ndef.Message(data);
+                sel.add_carrier(message[0], "active", message[1:])
+
+        print "Handover select:"
+        print sel.pretty()
+        print str(sel).encode("hex")
+
+        print "Sending handover select"
+        return sel
+
+
+def wps_handover_resp(peer):
+    print "Trying to handle WPS handover"
+
+    srv = HandoverServer()
+    srv.sent_carrier = None
+
+    nfc.llcp.activate(peer);
+
+    try:
+        print "Trying handover";
+        srv.start()
+        print "Wait for disconnect"
+        while nfc.llcp.connected():
+            time.sleep(0.1)
+        print "Disconnected after handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        return
+
+    if srv.sent_carrier:
+        wpas_report_handover(srv.received_carrier, srv.sent_carrier)
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    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 hostapd"
+                wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    print "Remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_config_tag(clf):
+    print "Write WPS config token"
+    data = wpas_get_config_token()
+    if (data == None):
+        print "Could not get WPS config token from hostapd"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+    print "Write WPS password token"
+    data = wpas_get_password_token()
+    if (data == None):
+        print "Could not get WPS password token from hostapd"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def find_peer(clf):
+    while True:
+        if nfc.llcp.connected():
+            print "LLCP connected"
+        general_bytes = nfc.llcp.startup({})
+        peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "listen -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        peer = clf.poll(general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "poll -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        if peer:
+            print "Found tag"
+            return peer
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+            wps_write_config_tag(clf)
+            raise SystemExit
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+            wps_write_password_tag(clf)
+            raise SystemExit
+
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            tag = find_peer(clf)
+            if isinstance(tag, nfc.DEP):
+                wps_handover_resp(tag)
+                continue
+
+            if tag.ndef:
+                wps_tag_read(tag)
+                continue
+
+            print "Not an NDEF tag - remove tag"
+            while tag.is_present:
+                time.sleep(0.1)
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
index d17ed61..75e5984 100644 (file)
@@ -2,14 +2,8 @@
  * hwsim_test - Data connectivity test for mac80211_hwsim
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <stdlib.h>
diff --git a/packaging/wpa_supplicant.changes b/packaging/wpa_supplicant.changes
deleted file mode 100644 (file)
index 4169d8e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-* Mon Jul 30 09:05:05 CST 2012 Arron <arron.wang@intel.com>
-- Fix BCM4334 first scan
-- BCM4334 is not support MAX SCAN SSID
-
-* Tue Jul 17 2012 Patrick McCarty <patrick.mccarty@linux.intel.com> 725b53c
-- systemd: fix service file activation issue
-
-* Tue Jul 17 2012 Anas Nashif <anas.nashif@intel.com> 90cf5c2
-- SYSTEMD: Use sysconfig file for different device options
-
-* Fri Jul 13 2012 Patrick McCarty <patrick.mccarty@linux.intel.com> 8451b2f
-- Install the upstream systemd service file
-
-* Fri Jun 15 2012 Chris Leech <christopher.leech@linux.intel.com> - 0.8.0
-- move dbus files from /usr/etc to /etc
-
-* Tue Jun 12 2012 Anas Nashif <anas.nashif@intel.com> e0f4a27
-- rename package name to be compatible with the world
-
-* Wed May 30 2012 Ryan Ware <ryan.r.ware@intel.com> 58ea2b5
-- Add default Smack manifest for wpasupplicant.spec
-
-* Sun Apr 29 2012 Kim Kibum <kb0929.kim@samsung.com> 8305339
-- upload tizen1.0 source
-
-* Mon Feb 27 2012 Kibum Kim <kb0929.kim@samsung.com> 0f0695f
-- tizen beta release
-
index 017d22d..8b43ace 100644 (file)
@@ -1,5 +1,25 @@
 <manifest>
- <request>
-    <domain name="_"/>
- </request>
-</manifest>
+       <define>
+               <domain name="wpasupplicant"/>
+               <request>
+                       <smack request="dbus" type="rwx"/>
+               </request>
+               <permit>
+                       <smack permit="dbus" type="rwx"/>
+               </permit>
+       </define>
+       <assign>
+               <filesystem path="/etc/dbus-1/system.d/wpa_supplicant.conf" label="_"/>
+               <filesystem path="/usr/lib/systemd/system/network.target.wants/wpa_supplicant.service" label="_"/>
+               <filesystem path="/usr/lib/systemd/system/wpa_supplicant.service" label="_"/>
+               <filesystem path="/usr/share/dbus-1/services/fi.w1.wpa_supplicant1.service" label="_"/>
+               <filesystem path="/usr/share/dbus-1/services/fi.epitest.hostap.WPASupplicant.service" label="_"/>
+               <filesystem path="/usr/share/doc/wpasupplicant/README.wpa_supplicant.conf.gz" label="_"/>
+               <filesystem path="/etc/rc.d/init.d/wpa_supplicant" label="_" exec_label="none"/>
+               <filesystem path="/etc/rc.d/rc3.d/S62wpasupplicant" label="_" exec_label="none"/>
+               <filesystem path="/etc/rc.d/rc5.d/S62wpasupplicant" label="_" exec_label="none"/>
+       </assign>
+       <request>
+               <domain name="wpasupplicant"/>
+       </request>
+</manifest>
\ No newline at end of file
diff --git a/packaging/wpa_supplicant.spec b/packaging/wpa_supplicant.spec
deleted file mode 100644 (file)
index c68ab23..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-Name:           wpa_supplicant
-Version:        0.8.0
-Release:        8
-License:        BSD license
-Summary:        Support for WPA and WPA2 (IEEE 802)
-Group:          System/Network
-Source0:        %{name}-%{version}.tar.gz
-Source1:        wpa_supplicant.service
-Source1001:     wpa_supplicant.manifest
-
-BuildRequires:  pkgconfig(dbus-1)
-BuildRequires:  pkgconfig(libcrypto)
-BuildRequires:  pkgconfig(libnl-2.0)
-BuildRequires:  pkgconfig(libssl)
-BuildRequires:  pkgconfig(openssl)
-Requires(post): /sbin/ldconfig
-Requires(postun): /sbin/ldconfig
-
-%description
-WPA and WPA2 are methods for securing wireless networks, the former
-using IEEE 802.1X, and the latter using IEEE 802.11i. This software
-provides key negotiation with the WPA Authenticator, and controls
-association with IEEE 802.11i networks.
-
-%prep
-%setup -q
-
-%build
-cp %{SOURCE1001} .
-cp -v configurations/tizen.config wpa_supplicant/.config
-cd wpa_supplicant
-make %{?_smp_mflags} all
-
-%install
-mkdir -p %{buildroot}%{_sbindir}/systemd/
-mkdir -p %{buildroot}%{_sbindir}/dbus/
-cd wpa_supplicant
-%make_install
-
-# D-Bus
-mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/
-cp dbus/dbus-wpa_supplicant.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/wpa_supplicant.conf
-mkdir -p %{buildroot}%{_datadir}/dbus-1/services/
-cp dbus/fi.epitest.hostap.WPASupplicant.service %{buildroot}%{_datadir}/dbus-1/services/
-cp dbus/fi.w1.wpa_supplicant1.service %{buildroot}%{_datadir}/dbus-1/services/
-
-mkdir -p %{buildroot}%{_sysconfdir}/rc.d/init.d
-cp ../etc/rc.d/init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/init.d/wpa_supplicant
-mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc3.d/
-ln -s ../init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/rc3.d/S62wpasupplicant
-mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc5.d/
-ln -s ../init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/rc5.d/S62wpasupplicant
-
-# sanitise the example configuration
-mkdir -p %{buildroot}%{_datadir}/doc/wpasupplicant
-sed 's/^\([^#]\+=.*\|}\)/#\1/' < ./wpa_supplicant.conf | gzip > %{buildroot}%{_datadir}/doc/wpasupplicant/README.wpa_supplicant.conf.gz
-
-# install systemd service file
-mkdir -p %{buildroot}%{_libdir}/systemd/system
-install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/
-mkdir -p %{buildroot}%{_libdir}/systemd/system/network.target.wants
-ln -s ../wpa_supplicant.service %{buildroot}%{_libdir}/systemd/system/network.target.wants/wpa_supplicant.service
-
-rm -rf %{buildroot}%{_sbindir}/systemd/
-rm -rf %{buildroot}%{_sbindir}/dbus/
-rm -rf %{buildroot}%{_sbindir}/wpa_passphrase
-
-%post -p /sbin/ldconfig
-
-%postun -p /sbin/ldconfig
-
-
-%files
-%manifest wpa_supplicant.manifest
-%{_sbindir}/wpa_cli
-%{_sbindir}/wpa_supplicant
-%attr(644,-,-) %{_sysconfdir}/dbus-1/system.d/*.conf
-%attr(644,-,-) %{_datadir}/dbus-1/services/*.service
-%{_defaultdocdir}/wpasupplicant/README.wpa_supplicant.*
-%{_sysconfdir}/rc.d/init.d/wpa_supplicant
-%{_sysconfdir}/rc.d/rc3.d/S62wpasupplicant
-%{_sysconfdir}/rc.d/rc5.d/S62wpasupplicant
-%{_libdir}/systemd/system/wpa_supplicant.service
-%{_libdir}/systemd/system/network.target.wants/wpa_supplicant.service
diff --git a/packaging/wpasupplicant.spec b/packaging/wpasupplicant.spec
new file mode 100644 (file)
index 0000000..9fcd39d
--- /dev/null
@@ -0,0 +1,99 @@
+Name:      wpasupplicant
+Summary:    Support for WPA and WPA2 (IEEE 802.11i / RSN)
+Version:    2.1.6
+Release:    1
+Group:      System/Network
+License:    BSD-2.0
+Source0:    %{name}-%{version}.tar.gz
+#Source1:        wpa_supplicant.service
+Source1001:     wpa_supplicant.manifest
+
+BuildRequires: pkgconfig(openssl)
+BuildRequires: pkgconfig(libssl)
+BuildRequires: pkgconfig(libcrypto)
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: pkgconfig(libnl-2.0)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description
+WPA and WPA2 are methods for securing wireless networks, the former
+using IEEE 802.1X, and the latter using IEEE 802.11i. This software
+provides key negotiation with the WPA Authenticator, and controls
+association with IEEE 802.11i networks.
+
+%prep
+%setup -q
+
+%build
+cp %{SOURCE1001} .
+cp -v configurations/tizen.config wpa_supplicant/.config
+cp -v configurations/tizen_hostapd.config hostapd/.config
+make %{?_smp_mflags} -C wpa_supplicant all
+make -C hostapd clean
+make %{?_smp_mflags} -C hostapd all
+
+%install
+mkdir -p %{buildroot}%{_sbindir}/systemd/
+mkdir -p %{buildroot}%{_sbindir}/dbus/
+
+cp -v wpa_supplicant/wpa_supplicant %{buildroot}%{_sbindir}/
+cp -v wpa_supplicant/wpa_cli %{buildroot}%{_sbindir}/
+cp -v hostapd/hostapd %{buildroot}%{_sbindir}/
+cp -v hostapd/hostapd_cli %{buildroot}%{_sbindir}/
+cp -v files/wpa_supp.sh %{buildroot}%{_sbindir}/
+
+# Configurations
+mkdir -p %{buildroot}%{_sysconfdir}/wpa_supplicant/
+cp -v wpa_supplicant/wpa_supplicant.conf %{buildroot}%{_sysconfdir}/wpa_supplicant/wpa_supplicant.conf
+cp -v hostapd/hostapd.conf %{buildroot}%{_sysconfdir}/wpa_supplicant/hostapd.conf
+
+# D-Bus
+#mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+#cp wpa_supplicant/dbus/dbus-wpa_supplicant.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/wpa_supplicant.conf
+mkdir -p %{buildroot}%{_datadir}/dbus-1/services/
+cp wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service %{buildroot}%{_datadir}/dbus-1/services/
+cp wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service %{buildroot}%{_datadir}/dbus-1/services/
+
+mkdir -p %{buildroot}%{_sysconfdir}/rc.d/init.d
+cp etc/rc.d/init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/init.d/wpa_supplicant
+mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc3.d/
+ln -s ../init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/rc3.d/S62wpasupplicant
+mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc5.d/
+ln -s ../init.d/wpa_supplicant %{buildroot}%{_sysconfdir}/rc.d/rc5.d/S62wpasupplicant
+
+# sanitise the example configuration
+mkdir -p %{buildroot}%{_defaultdocdir}/wpasupplicant
+sed 's/^\([^#]\+=.*\|}\)/#\1/' < ./wpa_supplicant/wpa_supplicant.conf | gzip > %{buildroot}%{_defaultdocdir}/wpasupplicant/README.wpa_supplicant.conf.gz
+
+# install systemd service file
+#mkdir -p %{buildroot}%{_libdir}/systemd/system
+#install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/
+#mkdir -p %{buildroot}%{_libdir}/systemd/system/network.target.wants
+#ln -s ../wpa_supplicant.service %{buildroot}%{_libdir}/systemd/system/network.target.wants/wpa_supplicant.service
+
+rm -rf %{buildroot}%{_sbindir}/systemd/
+rm -rf %{buildroot}%{_sbindir}/dbus/
+rm -rf %{buildroot}%{_sbindir}/wpa_passphrase
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%manifest wpa_supplicant.manifest
+%{_sbindir}/wpa_cli
+%{_sbindir}/wpa_supplicant
+%{_sbindir}/hostapd
+%{_sbindir}/hostapd_cli
+%attr(500,root,root) %{_sbindir}/wpa_supp.sh
+#%attr(644,-,-) %{_sysconfdir}/dbus-1/system.d/*.conf
+%attr(644,-,-) %{_datadir}/dbus-1/services/*.service
+%attr(644,-,-) %{_sysconfdir}/wpa_supplicant/*.conf
+%{_defaultdocdir}/wpasupplicant/README.wpa_supplicant.*
+%{_sysconfdir}/rc.d/init.d/wpa_supplicant
+%{_sysconfdir}/rc.d/rc3.d/S62wpasupplicant
+%{_sysconfdir}/rc.d/rc5.d/S62wpasupplicant
+#%{_libdir}/systemd/system/wpa_supplicant.service
+#%{_libdir}/systemd/system/network.target.wants/wpa_supplicant.service
diff --git a/patches/openssl-0.9.8x-tls-extensions.patch b/patches/openssl-0.9.8x-tls-extensions.patch
new file mode 100644 (file)
index 0000000..d1c0dbe
--- /dev/null
@@ -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@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
diff --git a/radius_example/.gitignore b/radius_example/.gitignore
new file mode 100644 (file)
index 0000000..c43e0fa
--- /dev/null
@@ -0,0 +1,2 @@
+*.d
+radius_example
index 7669fa3..ec458e3 100644 (file)
@@ -1,12 +1,8 @@
 Example application using RADIUS client as a library
 Copyright (c) 2007, Jouni Malinen <j@w1.fi>
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-Alternatively, this software may be distributed under the terms of BSD
-license.
+This software may be distributed under the terms of the BSD license.
+See the parent directory README for more details.
 
 
 This directory contains an example showing how the RADIUS client
index fd7dbae..cb0e154 100644 (file)
@@ -2,14 +2,8 @@
  * Example application using RADIUS client as a library
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -94,7 +88,8 @@ static void start_example(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL);
+       if (radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL) < 0)
+               radius_msg_free(msg);
 }
 
 
index 03421b3..9540531 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -32,8 +26,8 @@
  * 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 void accounting_sta_interim(struct hostapd_data *hapd,
+                                  struct sta_info *sta);
 
 
 static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
@@ -45,6 +39,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        u8 *val;
        size_t len;
        int i;
+       struct wpabuf *b;
 
        msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
                             radius_client_get_id(hapd->radius));
@@ -73,7 +68,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+       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)) {
@@ -82,7 +79,17 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        }
 
        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));
@@ -97,70 +104,11 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                }
        }
 
-       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");
+       if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
+                                  msg) < 0)
                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);
@@ -173,6 +121,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                                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;
@@ -242,7 +208,6 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
        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",
@@ -265,8 +230,9 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
                               hapd, sta);
 
        msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
-       if (msg)
-               radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
+       if (msg &&
+           radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+               radius_msg_free(msg);
 
        sta->acct_session_started = 1;
 }
@@ -364,9 +330,10 @@ static void accounting_sta_report(struct hostapd_data *hapd,
                goto fail;
        }
 
-       radius_client_send(hapd->radius, msg,
-                          stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
-                          sta->addr);
+       if (radius_client_send(hapd->radius, msg,
+                              stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+                              sta->addr) < 0)
+               goto fail;
        return;
 
  fail:
@@ -379,7 +346,8 @@ static void accounting_sta_report(struct hostapd_data *hapd,
  * @hapd: hostapd BSS data
  * @sta: The station
  */
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
+static void accounting_sta_interim(struct hostapd_data *hapd,
+                                  struct sta_info *sta)
 {
        if (sta->acct_session_started)
                accounting_sta_report(hapd, sta, 0);
@@ -406,7 +374,7 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
-static void accounting_sta_get_id(struct hostapd_data *hapd,
+void accounting_sta_get_id(struct hostapd_data *hapd,
                                  struct sta_info *sta)
 {
        sta->acct_session_id_lo = hapd->acct_session_id_lo++;
@@ -469,7 +437,8 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
                return;
        }
 
-       radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+       if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+               radius_msg_free(msg);
 }
 
 
index f3d60f0..dcc54ee 100644 (file)
@@ -2,21 +2,19 @@
  * hostapd / RADIUS Accounting
  * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README 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_get_id(struct hostapd_data *hapd,
+                                        struct sta_info *sta)
+{
+}
+
 static inline void accounting_sta_start(struct hostapd_data *hapd,
                                        struct sta_info *sta)
 {
@@ -36,6 +34,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
 {
 }
 #else /* CONFIG_NO_ACCOUNTING */
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
 void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
 int accounting_init(struct hostapd_data *hapd);
index b24cd90..c7748da 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -93,6 +87,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #ifdef CONFIG_IEEE80211R
        bss->ft_over_ds = 1;
 #endif /* CONFIG_IEEE80211R */
+
+       bss->radius_das_time_window = 300;
+
+       bss->sae_anti_clogging_threshold = 5;
 }
 
 
@@ -108,9 +106,9 @@ struct hostapd_config * hostapd_config_defaults(void)
        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 };
+               { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
        const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
-               { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
+               { 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 =
@@ -162,6 +160,17 @@ struct hostapd_config * hostapd_config_defaults(void)
 
        conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
 
+       conf->ap_table_max_size = 255;
+       conf->ap_table_expiration_time = 60;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       conf->ignore_probe_probability = 0.0d;
+       conf->ignore_auth_probability = 0.0d;
+       conf->ignore_assoc_probability = 0.0d;
+       conf->ignore_reassoc_probability = 0.0d;
+       conf->corrupt_gtk_rekey_mic_probability = 0.0d;
+#endif /* CONFIG_TESTING_OPTIONS */
+
        return conf;
 }
 
@@ -342,6 +351,30 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *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);
@@ -388,6 +421,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                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);
@@ -398,12 +432,15 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                                   conf->radius->num_auth_servers);
        hostapd_config_free_radius(conf->radius->acct_servers,
                                   conf->radius->num_acct_servers);
+       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->ocsp_stapling_response);
        os_free(conf->dh_file);
        os_free(conf->pac_opaque_encr_key);
        os_free(conf->eap_fast_a_id);
@@ -412,6 +449,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        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;
@@ -468,13 +506,32 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        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);
+
+       os_free(conf->sae_groups);
 }
 
 
@@ -550,11 +607,23 @@ int hostapd_rate_found(int *list, int rate)
 }
 
 
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_id_valid(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 1;
+               v = v->next;
+       }
+       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)
                        return v->ifname;
                v = v->next;
        }
@@ -579,57 +648,3 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 
        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;
-}
index cc7122c..1124920 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HOSTAPD_CONFIG_H
@@ -18,6 +12,7 @@
 #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
@@ -54,9 +49,10 @@ typedef enum hostap_security_policy {
 } secpolicy;
 
 struct hostapd_ssid {
-       char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+       u8 ssid[HOSTAPD_MAX_SSID_LEN];
        size_t ssid_len;
-       int ssid_set;
+       unsigned int ssid_set:1;
+       unsigned int utf8_ssid:1;
 
        char vlan[IFNAMSIZ + 1];
        secpolicy security_policy;
@@ -71,6 +67,10 @@ struct hostapd_ssid {
 #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 */
@@ -97,6 +97,11 @@ struct hostapd_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;
@@ -122,6 +127,12 @@ struct hostapd_eap_user {
        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
 
@@ -132,14 +143,6 @@ struct hostapd_tx_queue_params {
        int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
 };
 
-struct hostapd_wmm_ac_params {
-       int cwmin;
-       int cwmax;
-       int aifs;
-       int txop_limit; /* in units of 32us */
-       int admission_control_mandatory;
-};
-
 
 #define MAX_ROAMING_CONSORTIUM_LEN 15
 
@@ -148,12 +151,36 @@ struct hostapd_roaming_consortium {
        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 vlan_bridge[IFNAMSIZ + 1];
        char wds_bridge[IFNAMSIZ + 1];
 
        enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -172,11 +199,21 @@ struct hostapd_bss_config {
        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;
 
@@ -258,6 +295,7 @@ struct hostapd_bss_config {
        char *private_key;
        char *private_key_passwd;
        int check_crl;
+       char *ocsp_stapling_response;
        char *dh_file;
        u8 *pac_opaque_encr_key;
        u8 *eap_fast_a_id;
@@ -304,6 +342,7 @@ struct hostapd_bss_config {
 
        int wps_state;
 #ifdef CONFIG_WPS
+       int wps_independent;
        int ap_setup_locked;
        u8 uuid[16];
        char *wps_pin_requests;
@@ -329,6 +368,11 @@ struct hostapd_bss_config {
        char *model_url;
        char *upc;
        struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+       int wps_nfc_pw_from_config;
+       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;
 
@@ -340,15 +384,19 @@ struct hostapd_bss_config {
        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;
@@ -366,11 +414,54 @@ struct hostapd_bss_config {
        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;
+
+       unsigned int sae_anti_clogging_threshold;
+       int *sae_groups;
 };
 
 
@@ -409,6 +500,8 @@ struct hostapd_config {
 
        int ieee80211d;
 
+       int ieee80211h; /* DFS */
+
        struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
 
        /*
@@ -425,6 +518,20 @@ struct hostapd_config {
        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;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       double ignore_probe_probability;
+       double ignore_auth_probability;
+       double ignore_assoc_probability;
+       double ignore_reassoc_probability;
+       double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -441,10 +548,10 @@ int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
 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);
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
 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);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 
 #endif /* HOSTAPD_CONFIG_H */
index 429c187..8205d13 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - Driver operations
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.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"
 
 
@@ -153,6 +149,38 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
        }
 #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 */
+
+       if (hapd->conf->vendor_elements) {
+               size_t add = wpabuf_len(hapd->conf->vendor_elements);
+               if (wpabuf_resize(&beacon, add) == 0)
+                       wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
+               if (wpabuf_resize(&proberesp, add) == 0)
+                       wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
+       }
+
        *beacon_ret = beacon;
        *proberesp_ret = proberesp;
        *assocresp_ret = assocresp;
@@ -318,6 +346,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    const u8 *supp_rates, size_t supp_rates_len,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
+                   const struct ieee80211_vht_capabilities *vht_capab,
                    u32 flags, u8 qosinfo)
 {
        struct hostapd_sta_add_params params;
@@ -335,6 +364,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
        params.supp_rates_len = supp_rates_len;
        params.listen_interval = listen_interval;
        params.ht_capabilities = ht_capab;
+       params.vht_capabilities = vht_capab;
        params.flags = hostapd_sta_flags_to_drv(flags);
        params.qosinfo = qosinfo;
        return hapd->driver->sta_add(hapd->drv_priv, &params);
@@ -434,19 +464,76 @@ 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 channel, int ht_enabled, int vht_enabled,
+                    int sec_channel_offset, int vht_oper_chwidth,
+                    int center_segment0, int center_segment1)
 {
        struct hostapd_freq_params data;
-       if (hapd->driver == NULL)
-               return 0;
-       if (hapd->driver->set_freq == NULL)
-               return 0;
+       int tmp;
+
        os_memset(&data, 0, sizeof(data));
        data.mode = mode;
        data.freq = freq;
        data.channel = channel;
        data.ht_enabled = ht_enabled;
+       data.vht_enabled = vht_enabled;
        data.sec_channel_offset = sec_channel_offset;
+       data.center_freq1 = freq + sec_channel_offset * 10;
+       data.center_freq2 = 0;
+       data.bandwidth = sec_channel_offset ? 40 : 20;
+
+       /*
+        * This validation code is probably misplaced, maybe it should be
+        * in src/ap/hw_features.c and check the hardware support as well.
+        */
+       if (data.vht_enabled) switch (vht_oper_chwidth) {
+       case VHT_CHANWIDTH_USE_HT:
+               if (center_segment1)
+                       return -1;
+               if (5000 + center_segment0 * 5 != data.center_freq1)
+                       return -1;
+               break;
+       case VHT_CHANWIDTH_80P80MHZ:
+               if (center_segment1 == center_segment0 + 4 ||
+                   center_segment1 == center_segment0 - 4)
+                       return -1;
+               data.center_freq2 = 5000 + center_segment1 * 5;
+               /* fall through */
+       case VHT_CHANWIDTH_80MHZ:
+               data.bandwidth = 80;
+               if (vht_oper_chwidth == 1 && center_segment1)
+                       return -1;
+               if (vht_oper_chwidth == 3 && !center_segment1)
+                       return -1;
+               if (!sec_channel_offset)
+                       return -1;
+               /* primary 40 part must match the HT configuration */
+               tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
+               tmp /= 2;
+               if (data.center_freq1 != 5000 +
+                                        center_segment0 * 5 - 20 + 40 * tmp)
+                       return -1;
+               data.center_freq1 = 5000 + center_segment0 * 5;
+               break;
+       case VHT_CHANWIDTH_160MHZ:
+               data.bandwidth = 160;
+               if (center_segment1)
+                       return -1;
+               if (!sec_channel_offset)
+                       return -1;
+               /* primary 40 part must match the HT configuration */
+               tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
+               tmp /= 2;
+               if (data.center_freq1 != 5000 +
+                                        center_segment0 * 5 - 60 + 40 * tmp)
+                       return -1;
+               data.center_freq1 = 5000 + center_segment0 * 5;
+               break;
+       }
+       if (hapd->driver == NULL)
+               return 0;
+       if (hapd->driver->set_freq == NULL)
+               return 0;
        return hapd->driver->set_freq(hapd->drv_priv, &data);
 }
 
@@ -590,3 +677,25 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
        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);
+}
index 835cdde..70fab55 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - Driver operations
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AP_DRV_OPS
@@ -19,6 +13,7 @@ enum wpa_driver_if_type;
 struct wpa_bss_params;
 struct wpa_driver_scan_params;
 struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
 int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -43,6 +38,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    const u8 *supp_rates, size_t supp_rates_len,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
+                   const struct ieee80211_vht_capabilities *vht_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,
@@ -61,7 +57,9 @@ 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 channel, int ht_enabled, int vht_enabled,
+                    int sec_channel_offset, int vht_oper_chwidth,
+                    int center_segment0, int center_segment1);
 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,
@@ -92,6 +90,9 @@ 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,
@@ -104,6 +105,10 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
 
 #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)
 {
@@ -168,6 +173,14 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
        return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
 }
 
+static inline int hostapd_drv_set_acl(struct hostapd_data *hapd,
+                                     struct hostapd_acl_params *params)
+{
+       if (hapd->driver == NULL || hapd->driver->set_acl == NULL)
+               return 0;
+       return hapd->driver->set_acl(hapd->drv_priv, params);
+}
+
 static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
                                     struct wpa_driver_ap_params *params)
 {
index 9b9fc9e..9f02151 100644 (file)
@@ -4,14 +4,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -56,7 +50,7 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
 }
 
 
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
 {
        struct ap_info *s;
 
@@ -93,34 +87,6 @@ static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
 }
 
 
-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)];
@@ -154,7 +120,6 @@ 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);
@@ -177,25 +142,6 @@ static void hostapd_free_aps(struct hostapd_iface *iface)
 }
 
 
-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;
@@ -209,7 +155,6 @@ static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
        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 "
@@ -229,7 +174,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
        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)
@@ -245,37 +189,9 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
                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;
+       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);
 
        if (elems->erp_info && elems->erp_info_len == 1)
                ap->erp = elems->erp_info[0];
@@ -284,6 +200,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
 
        if (elems->ds_params && elems->ds_params_len == 1)
                ap->channel = elems->ds_params[0];
+       else if (elems->ht_operation && elems->ht_operation_len >= 1)
+               ap->channel = elems->ht_operation[0];
        else if (fi)
                ap->channel = fi->channel;
 
@@ -292,13 +210,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
        else
                ap->ht_support = 0;
 
-       ap->num_beacons++;
        os_get_time(&now);
        ap->last_beacon = now.sec;
-       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
@@ -310,23 +223,29 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
        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));
+               wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
+                          " (channel %d) - enable protection",
+                          MAC2STR(ap->addr), ap->channel);
                set_beacon++;
        }
 
 #ifdef CONFIG_IEEE80211N
-       if (!iface->olbc_ht && !ap->ht_support) {
+       if (!iface->olbc_ht && !ap->ht_support &&
+           (ap->channel == 0 ||
+            ap->channel == iface->conf->channel ||
+            ap->channel == iface->conf->channel +
+            iface->conf->secondary_channel * 4)) {
                iface->olbc_ht = 1;
                hostapd_ht_operation_update(iface);
                wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
-                          " - enable protection", MAC2STR(ap->addr));
+                          " (channel %d) - enable protection",
+                          MAC2STR(ap->addr), ap->channel);
                set_beacon++;
        }
 #endif /* CONFIG_IEEE80211N */
 
        if (set_beacon)
-               ieee802_11_set_beacons(iface);
+               ieee802_11_update_beacons(iface);
 }
 
 
@@ -381,7 +300,7 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
        }
 
        if (set_beacon)
-               ieee802_11_set_beacons(iface);
+               ieee802_11_update_beacons(iface);
 }
 
 
index 6df8981..d0529a1 100644 (file)
@@ -4,14 +4,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef 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. */
+        * entries. */
        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 */
        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,
index 2b09b11..a959694 100644 (file)
@@ -4,14 +4,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index c77a939..e7fd69d 100644 (file)
@@ -4,14 +4,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MLME_H
index 6f56c95..597b8dd 100644 (file)
@@ -2,14 +2,8 @@
  * Authentication server setup
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -98,7 +92,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
        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.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;
@@ -154,6 +148,8 @@ int authsrv_init(struct hostapd_data *hapd)
                params.private_key = hapd->conf->private_key;
                params.private_key_passwd = hapd->conf->private_key_passwd;
                params.dh_file = hapd->conf->dh_file;
+               params.ocsp_stapling_response =
+                       hapd->conf->ocsp_stapling_response;
 
                if (tls_global_set_params(hapd->ssl_ctx, &params)) {
                        wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
index be3051e..2f4ed34 100644 (file)
@@ -2,14 +2,8 @@
  * Authentication server setup
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AUTHSRV_H
index 4d8b277..2fbd527 100644 (file)
@@ -2,7 +2,7 @@
  * 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@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -33,6 +33,7 @@
 #include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
 #include "beacon.h"
+#include "hs20.h"
 
 
 #ifdef NEED_AP_MLME
@@ -205,6 +206,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        if (hapd->p2p_probe_resp_ie)
                buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
 #endif /* CONFIG_P2P */
+       if (hapd->conf->vendor_elements)
+               buflen += wpabuf_len(hapd->conf->vendor_elements);
        resp = os_zalloc(buflen);
        if (resp == NULL)
                return NULL;
@@ -262,6 +265,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        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);
 
@@ -287,13 +295,64 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
                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)
+                     const struct ieee80211_mgmt *mgmt, size_t len,
+                     int ssi_signal)
 {
        u8 *resp;
        struct ieee802_11_elems elems;
@@ -302,17 +361,19 @@ void handle_probe_req(struct hostapd_data *hapd,
        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));
-
+#ifndef TIZEN_EXT_P2P
        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) > 0)
+                                           ie, ie_len, ssi_signal) > 0)
                        return;
+#endif
 
        if (!hapd->iconf->send_probe_response)
                return;
@@ -343,9 +404,22 @@ void handle_probe_req(struct hostapd_data *hapd,
                }
                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) {
+       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;
@@ -363,10 +437,9 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_P2P */
 
-       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)) {
+       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 {
@@ -375,9 +448,10 @@ void handle_probe_req(struct hostapd_data *hapd,
                        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 ")",
+                                  " for foreign SSID '%s' (DA " MACSTR ")%s",
                                   MAC2STR(mgmt->sa), ssid_txt,
-                                  MAC2STR(mgmt->da));
+                                  MAC2STR(mgmt->da),
+                                  elems.ssid_list ? " (SSID list)" : "");
                }
                return;
        }
@@ -412,9 +486,30 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+           supp_rates_11b_only(&elems)) {
+               /* Indicates support for 11b rates only */
+               wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
+                          MACSTR " with only 802.11b rates",
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+#endif /* CONFIG_P2P */
+
        /* TODO: verify that supp_rates contains at least one matching rate
         * with AP configuration */
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->iconf->ignore_probe_probability > 0.0d &&
+           drand48() < hapd->iconf->ignore_probe_probability) {
+               wpa_printf(MSG_INFO,
+                          "TESTING: ignoring probe request from " MACSTR,
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
                                      &resp_len);
        if (resp == NULL)
@@ -424,7 +519,8 @@ void handle_probe_req(struct hostapd_data *hapd,
         * If this is a broadcast probe request, apply no ack policy to avoid
         * excessive retries.
         */
-       noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
+       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");
@@ -505,6 +601,8 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        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");
@@ -582,6 +680,11 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        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);
 
@@ -606,6 +709,16 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
                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);
@@ -620,8 +733,8 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        params.proberesp_len = resp_len;
        params.dtim_period = hapd->conf->dtim_period;
        params.beacon_int = hapd->iconf->beacon_int;
-       params.basic_rates = hapd->iconf->basic_rates;
-       params.ssid = (u8 *) hapd->conf->ssid.ssid;
+       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;
@@ -670,6 +783,10 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
            !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);
@@ -687,4 +804,14 @@ void ieee802_11_set_beacons(struct hostapd_iface *iface)
                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 */
index a944f5f..37f10d2 100644 (file)
 struct ieee80211_mgmt;
 
 void handle_probe_req(struct hostapd_data *hapd,
-                     const struct ieee80211_mgmt *mgmt, size_t len);
+                     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 */
index d348dc1..1cb7e73 100644 (file)
@@ -2,19 +2,14 @@
  * Control interface for shared AP commands
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 "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,
@@ -62,6 +80,10 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
        if (res >= 0)
                len += res;
 
+       res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+       if (res >= 0)
+               len += res;
+
        return len;
 }
 
@@ -106,3 +128,178 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
        }               
        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;
+       u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+       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 */
+
+       pos = os_strstr(txtaddr, " reason=");
+       if (pos)
+               reason = atoi(pos + 8);
+
+       hostapd_drv_sta_deauth(hapd, addr, reason);
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               ap_sta_deauthenticate(hapd, sta, reason);
+       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;
+       u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+       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 */
+
+       pos = os_strstr(txtaddr, " reason=");
+       if (pos)
+               reason = atoi(pos + 8);
+
+       hostapd_drv_sta_disassoc(hapd, addr, reason);
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               ap_sta_disassociate(hapd, sta, reason);
+       else if (addr[0] == 0xff)
+               hostapd_free_stas(hapd);
+
+       return 0;
+}
index 8690bea..e83f894 100644 (file)
@@ -2,14 +2,8 @@
  * Control interface for shared AP commands
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_AP_H
@@ -21,5 +15,9 @@ 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 */
index b7febdc..7ea30ef 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / Callback functions for driver wrappers
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.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"
@@ -32,6 +28,7 @@
 #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,
@@ -42,7 +39,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        struct ieee802_11_elems elems;
        const u8 *ie;
        size_t ielen;
+#ifdef CONFIG_IEEE80211R
+       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) {
                /*
@@ -83,11 +85,21 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 
        sta = ap_get_sta(hapd, addr);
        if (sta) {
+               ap_sta_no_session_timeout(hapd, 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)
+               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);
 
@@ -99,6 +111,15 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        }
 #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
@@ -142,27 +163,85 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        return -1;
                }
                res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
-                                         ie, ielen, NULL, 0);
+                                         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)
+                       if (res == WPA_INVALID_GROUP) {
                                reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-                       else if (res == WPA_INVALID_PAIRWISE)
+                               status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+                       } else if (res == WPA_INVALID_PAIRWISE) {
                                reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
-                       else if (res == WPA_INVALID_AKMP)
+                               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)
+                       else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
                                reason = WLAN_REASON_INVALID_IE;
-                       else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+                               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
+                       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;
@@ -174,6 +253,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 #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;
                }
@@ -194,9 +274,24 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 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;
-       wpa_auth_sm_event(sta->wpa_sm, WPA_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);
 
@@ -212,6 +307,9 @@ skip_wpa_check:
        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;
@@ -245,6 +343,10 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
                return;
        }
 
+#if defined TIZEN_EXT
+       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
+       MAC2STR(sta->addr));
+#endif
        ap_sta_set_authorized(hapd, sta, 0);
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
        wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
@@ -270,8 +372,52 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
 }
 
 
+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 */
+}
+
+
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+                                        const u8 *addr, int reason_code)
+{
+       switch (reason_code) {
+       case MAX_CLIENT_REACHED:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
+                       MAC2STR(addr));
+               break;
+       case BLOCKED_CLIENT:
+               wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
+                       MAC2STR(addr));
+               break;
+       }
+}
+
+
 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)
+                        const u8 *bssid, const u8 *ie, size_t ie_len,
+                        int ssi_signal)
 {
        size_t i;
        int ret = 0;
@@ -282,7 +428,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
        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) > 0) {
+                                           sa, da, bssid, ie, ie_len,
+                                           ssi_signal) > 0) {
                        ret = 1;
                        break;
                }
@@ -293,6 +440,110 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
 
 #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_AP_UNABLE_TO_HANDLE_NEW_STA;
+                       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)
@@ -452,12 +703,15 @@ 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 (ap_get_sta(iface->bss[j], src)) {
-                       hapd = iface->bss[j];
-                       break;
+               if ((sta = ap_get_sta(iface->bss[j], src))) {
+                       if (sta->flags & WLAN_STA_ASSOC) {
+                               hapd = iface->bss[j];
+                               break;
+                       }
                }
        }
 
@@ -472,7 +726,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #ifndef CONFIG_NO_STDOUT_DEBUG
        int level = MSG_DEBUG;
 
-       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+       if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
            data->rx_mgmt.frame_len >= 24) {
                const struct ieee80211_hdr *hdr;
                u16 fc;
@@ -481,6 +735,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
                    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
                        level = MSG_EXCESSIVE;
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
+                       level = MSG_EXCESSIVE;
        }
 
        wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
@@ -547,7 +804,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                     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.ie_len,
+                                    data->rx_probe_req.ssi_signal);
                break;
        case EVENT_NEW_STA:
                hostapd_event_new_sta(hapd, data->new_sta.addr);
@@ -576,14 +834,32 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        break;
                hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
                break;
-#ifdef NEED_AP_MLME
        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);
-               break;
 #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;
+       case EVENT_CONNECT_FAILED_REASON:
+               if (!data)
+                       break;
+               hostapd_event_connect_failed_reason(
+                       hapd, data->connect_failed_reason.addr,
+                       data->connect_failed_reason.code);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "Unknown event %d", event);
                break;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
new file mode 100644 (file)
index 0000000..79d50e5
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_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;
+}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
new file mode 100644 (file)
index 0000000..b3574ba
--- /dev/null
@@ -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_cb2 = gas_serv_rx_public_action;
+       hapd->public_action_cb2_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)
+{
+}
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
new file mode 100644 (file)
index 0000000..4213cf6
--- /dev/null
@@ -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 */
index 0c5ee2e..780b2e2 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -18,6 +12,7 @@
 #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 "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);
+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)
@@ -85,7 +99,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
        hostapd_update_wps(hapd);
 
        if (hapd->conf->ssid.ssid_set &&
-           hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
+           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 */
@@ -94,24 +108,17 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
 }
 
 
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_clear_old(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]);
+               hostapd_flush_old_stations(iface->bss[j],
+                                          WLAN_REASON_PREV_AUTH_NOT_VALID);
                hostapd_broadcast_wep_clear(iface->bss[j]);
 
 #ifndef CONFIG_NO_RADIUS
@@ -120,6 +127,31 @@ int hostapd_reload_config(struct hostapd_iface *iface)
                radius_client_flush(iface->bss[j]->radius, 0);
 #endif /* CONFIG_NO_RADIUS */
        }
+}
+
+
+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_fname == NULL) {
+               /* Only in-memory config in use - assume it has been updated */
+               hostapd_clear_old(iface);
+               for (j = 0; j < iface->num_bss; j++)
+                       hostapd_reload_bss(iface->bss[j]);
+               return 0;
+       }
+
+       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;
+
+       hostapd_clear_old(iface);
 
        oldconf = hapd->iconf;
        iface->conf = newconf;
@@ -216,21 +248,9 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
        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);
 
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
        iapp_deinit(hapd->iapp);
        hapd->iapp = NULL;
        accounting_deinit(hapd);
@@ -240,6 +260,8 @@ static void hostapd_cleanup(struct hostapd_data *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);
@@ -263,6 +285,34 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
 #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);
 }
 
 
@@ -278,6 +328,18 @@ 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
@@ -287,13 +349,7 @@ static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
  */
 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;
-       os_free(iface->basic_rates);
-       iface->basic_rates = NULL;
-       ap_list_deinit(iface);
+       hostapd_cleanup_iface_partial(iface);
        hostapd_config_free(iface->conf);
        iface->conf = NULL;
 
@@ -303,6 +359,15 @@ static void hostapd_cleanup_iface(struct hostapd_iface *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;
@@ -339,7 +404,7 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 }
 
 
-static int hostapd_flush_old_stations(struct hostapd_data *hapd)
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
 {
        int ret = 0;
        u8 addr[ETH_ALEN];
@@ -355,7 +420,7 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd)
        }
        wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
        os_memset(addr, 0xff, ETH_ALEN);
-       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+       hostapd_drv_sta_deauth(hapd, addr, reason);
        hostapd_free_stas(hapd);
 
        return ret;
@@ -470,6 +535,86 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a)
 }
 
 
+#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 */
 
 
 /**
@@ -525,7 +670,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
        if (conf->wmm_enabled < 0)
                conf->wmm_enabled = hapd->iconf->ieee80211n;
 
-       hostapd_flush_old_stations(hapd);
+       hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
        hostapd_set_privacy(hapd, 0);
 
        hostapd_broadcast_wep_clear(hapd);
@@ -558,14 +703,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                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'",
+                          " and ssid \"%s\"",
                           hapd->conf->iface, MAC2STR(hapd->own_addr),
-                          hapd->conf->ssid.ssid);
+                          wpa_ssid_txt(hapd->conf->ssid.ssid,
+                                       hapd->conf->ssid.ssid_len));
        }
 
        if (hostapd_setup_wpa_psk(conf)) {
@@ -575,7 +720,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
 
        /* 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,
+       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;
@@ -589,6 +734,27 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                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)) {
@@ -621,8 +787,16 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                return -1;
        }
 
-       if (hapd->iface->ctrl_iface_init &&
-           hapd->iface->ctrl_iface_init(hapd)) {
+#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;
        }
@@ -663,6 +837,74 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
 }
 
 
+static int hostapd_set_acl_list(struct hostapd_data *hapd,
+                               struct mac_acl_entry *mac_acl,
+                               int n_entries, u8 accept_acl)
+{
+       struct hostapd_acl_params *acl_params;
+       int i, err;
+
+       acl_params = os_zalloc(sizeof(*acl_params) +
+                              (n_entries * sizeof(acl_params->mac_acl[0])));
+       if (!acl_params)
+               return -ENOMEM;
+
+       for (i = 0; i < n_entries; i++)
+               os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
+                         ETH_ALEN);
+
+       acl_params->acl_policy = accept_acl;
+       acl_params->num_mac_acl = n_entries;
+
+       err = hostapd_drv_set_acl(hapd, acl_params);
+
+       os_free(acl_params);
+
+       return err;
+}
+
+
+static void hostapd_set_acl(struct hostapd_data *hapd)
+{
+       struct hostapd_config *conf = hapd->iconf;
+       int err;
+       u8 accept_acl;
+
+       if (hapd->iface->drv_max_acl_mac_addrs == 0)
+               return;
+       if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+               return;
+
+       if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+               if (conf->bss->num_accept_mac) {
+                       accept_acl = 1;
+                       err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
+                                                  conf->bss->num_accept_mac,
+                                                  accept_acl);
+                       if (err) {
+                               wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+                               return;
+                       }
+               } else {
+                       wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+               }
+       } else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+               if (conf->bss->num_deny_mac) {
+                       accept_acl = 0;
+                       err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
+                                                  conf->bss->num_deny_mac,
+                                                  accept_acl);
+                       if (err) {
+                               wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+                               return;
+                       }
+               } else {
+                       wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+               }
+       }
+}
+
+
 static int setup_interface(struct hostapd_iface *iface)
 {
        struct hostapd_data *hapd = iface->bss[0];
@@ -736,7 +978,11 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
                if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
                                     hapd->iconf->channel,
                                     hapd->iconf->ieee80211n,
-                                    hapd->iconf->secondary_channel)) {
+                                    hapd->iconf->ieee80211ac,
+                                    hapd->iconf->secondary_channel,
+                                    hapd->iconf->vht_oper_chwidth,
+                                    hapd->iconf->vht_oper_centr_freq_seg0_idx,
+                                    hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
                        wpa_printf(MSG_ERROR, "Could not set channel for "
                                   "kernel driver");
                        return -1;
@@ -784,6 +1030,8 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 
        ap_list_init(iface);
 
+       hostapd_set_acl(hapd);
+
        if (hostapd_driver_commit(hapd) < 0) {
                wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
                           "configuration", __func__);
@@ -863,6 +1111,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
        hapd->conf = bss;
        hapd->iface = hapd_iface;
        hapd->driver = hapd->iconf->driver;
+       hapd->ctrl_sock = -1;
 
        return hapd;
 }
@@ -879,7 +1128,8 @@ void hostapd_interface_deinit(struct hostapd_iface *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_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+               hostapd_clear_wep(hapd);
                hostapd_cleanup(hapd);
        }
 }
@@ -894,6 +1144,293 @@ void hostapd_interface_free(struct hostapd_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
@@ -932,8 +1469,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *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)
+       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);
@@ -943,4 +1482,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
                        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);
 }
index 5b72768..75d9c66 100644 (file)
@@ -2,26 +2,20 @@
  * hostapd / Initialization and configuration
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 hapd_interfaces;
 struct hostapd_data;
 struct sta_info;
 struct hostap_sta_driver_data;
@@ -30,9 +24,33 @@ struct full_dynamic_vlan;
 enum wps_event;
 union wps_event_data;
 
+struct hostapd_iface;
+struct hostapd_dynamic_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;
+       size_t count_dynamic;
+       int global_ctrl_sock;
+       char *global_iface_path;
+       char *global_iface_name;
+       gid_t ctrl_iface_group;
+       struct hostapd_iface **iface;
+       struct hostapd_dynamic_iface **dynamic_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);
+                 const u8 *ie, size_t ie_len, int ssi_signal);
        void *ctx;
 };
 
@@ -46,7 +64,7 @@ struct hostapd_rate_data {
 struct hostapd_frame_info {
        u32 channel;
        u32 datarate;
-       u32 ssi_signal;
+       int ssi_signal; /* dBm */
 };
 
 
@@ -86,6 +104,7 @@ struct hostapd_data {
 
        struct radius_client_data *radius;
        u32 acct_session_id_hi, acct_session_id_lo;
+       struct radius_das_data *radius_das;
 
        struct iapp_data *iapp;
 
@@ -125,6 +144,7 @@ struct hostapd_data {
        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 */
@@ -135,6 +155,9 @@ struct hostapd_data {
        void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
                                 int freq);
        void *public_action_cb_ctx;
+       void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len,
+                                 int freq);
+       void *public_action_cb2_ctx;
 
        int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
                                int freq);
@@ -149,7 +172,7 @@ struct hostapd_data {
        void *wps_event_cb_ctx;
 
        void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
-                                 int authorized);
+                                 int authorized, const u8 *p2p_dev_addr);
        void *sta_authorized_cb_ctx;
 
        void (*setup_complete_cb)(void *ctx);
@@ -169,6 +192,19 @@ struct hostapd_data {
        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 */
+
+#ifdef CONFIG_SAE
+       /** Key used for generating SAE anti-clogging tokens */
+       u8 sae_token_key[8];
+       os_time_t last_sae_token_key_update;
+#endif /* CONFIG_SAE */
 };
 
 
@@ -178,8 +214,6 @@ struct hostapd_data {
 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;
 
@@ -189,7 +223,6 @@ struct hostapd_iface {
        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;
 
@@ -199,6 +232,12 @@ struct hostapd_iface {
         */
        unsigned int probe_resp_offloads;
 
+       /* extended capabilities supported by the driver */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
+
+       unsigned int drv_max_acl_mac_addrs;
+
        struct hostapd_hw_modes *hw_features;
        int num_hw_features;
        struct hostapd_hw_modes *current_mode;
@@ -237,16 +276,22 @@ struct hostapd_iface {
 
        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);
+/**
+ * struct hostapd_dynamic_iface - hostapd per dynamically allocated
+ * or added interface data structure
+ */
+struct hostapd_dynamic_iface {
+       char parent[IFNAMSIZ + 1];
+       char iface[IFNAMSIZ + 1];
+       unsigned int usage;
 };
 
 /* 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,
@@ -258,12 +303,19 @@ 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),
+                                          const u8 *ie, size_t ie_len,
+                                          int ssi_signal),
                                 void *ctx);
 void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
 
@@ -272,7 +324,16 @@ 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);
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+                                        const u8 *addr, int reason_code);
 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);
+                        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 */
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
new file mode 100644 (file)
index 0000000..45d518b
--- /dev/null
@@ -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;
+}
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
new file mode 100644 (file)
index 0000000..98698ce
--- /dev/null
@@ -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 */
index 8c6fef2..37112bd 100644 (file)
@@ -2,7 +2,7 @@
  * 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@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -122,6 +122,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
        case HOSTAPD_MODE_IEEE80211G:
                basic_rates = basic_rates_g;
                break;
+       case HOSTAPD_MODE_IEEE80211AD:
+               return 0; /* No basic rates for 11ad */
        default:
                return -1;
        }
@@ -129,6 +131,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
        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)
@@ -138,7 +142,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
        iface->num_rates = 0;
 
        iface->current_rates =
-               os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
+               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.");
@@ -416,7 +420,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
        int res;
 
        /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
-        * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
+        * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
 
        iface->scan_cb = NULL;
 
@@ -439,7 +443,6 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
                           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);
@@ -447,6 +450,46 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
 }
 
 
+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;
@@ -457,12 +500,15 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
        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 (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;
@@ -711,6 +757,8 @@ const char * hostapd_hw_mode_txt(int mode)
                return "IEEE 802.11b";
        case HOSTAPD_MODE_IEEE80211G:
                return "IEEE 802.11g";
+       case HOSTAPD_MODE_IEEE80211AD:
+               return "IEEE 802.11ad";
        default:
                return "UNKNOWN";
        }
index 115d91e..be55c69 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index 5fc01cb..c221183 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
  * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IAPP_H
index a1a7270..5503af1 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "common/sae.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "p2p/p2p.h"
@@ -40,6 +37,7 @@
 #include "ap_mlme.h"
 #include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
+#include "wnm_ap.h"
 #include "ieee802_11.h"
 
 
@@ -55,6 +53,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *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) {
                /* rest of the rates are encoded in Extended supported
                 * rates element */
@@ -72,9 +72,15 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
                pos++;
        }
 
-       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
-           hapd->iface->num_rates < 8)
+       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;
 }
@@ -91,6 +97,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *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;
@@ -109,9 +117,17 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
                pos++;
        }
 
-       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
-           hapd->iface->num_rates >= 8)
-               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+       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;
 }
@@ -302,6 +318,222 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
 #endif /* CONFIG_IEEE80211R */
 
 
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
+                                              struct sta_info *sta)
+{
+       struct wpabuf *buf;
+
+       if (hapd->conf->ssid.wpa_passphrase == NULL) {
+               wpa_printf(MSG_DEBUG, "SAE: No password available");
+               return NULL;
+       }
+
+       if (sae_prepare_commit(hapd->own_addr, sta->addr,
+                              (u8 *) hapd->conf->ssid.wpa_passphrase,
+                              os_strlen(hapd->conf->ssid.wpa_passphrase),
+                              sta->sae) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+               return NULL;
+       }
+
+       if (sae_process_commit(sta->sae) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+               return NULL;
+       }
+
+       buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+       if (buf == NULL)
+               return NULL;
+       sae_write_commit(sta->sae, buf, NULL);
+
+       return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+                                             struct sta_info *sta)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
+       if (buf == NULL)
+               return NULL;
+
+       sae_write_confirm(sta->sae, buf);
+
+       return buf;
+}
+
+
+static int use_sae_anti_clogging(struct hostapd_data *hapd)
+{
+       struct sta_info *sta;
+       unsigned int open = 0;
+
+       if (hapd->conf->sae_anti_clogging_threshold == 0)
+               return 1;
+
+       for (sta = hapd->sta_list; sta; sta = sta->next) {
+               if (!sta->sae)
+                       continue;
+               if (sta->sae->state != SAE_COMMITTED &&
+                   sta->sae->state != SAE_CONFIRMED)
+                       continue;
+               open++;
+               if (open >= hapd->conf->sae_anti_clogging_threshold)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
+                          const u8 *token, size_t token_len)
+{
+       u8 mac[SHA256_MAC_LEN];
+
+       if (token_len != SHA256_MAC_LEN)
+               return -1;
+       if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                       addr, ETH_ALEN, mac) < 0 ||
+           os_memcmp(token, mac, SHA256_MAC_LEN) != 0)
+               return -1;
+
+       return 0;
+}
+
+
+static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
+                                           const u8 *addr)
+{
+       struct wpabuf *buf;
+       u8 *token;
+       struct os_time t;
+
+       os_get_time(&t);
+       if (hapd->last_sae_token_key_update == 0 ||
+           t.sec > hapd->last_sae_token_key_update + 60) {
+               if (random_get_bytes(hapd->sae_token_key,
+                                    sizeof(hapd->sae_token_key)) < 0)
+                       return NULL;
+               wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
+                           hapd->sae_token_key, sizeof(hapd->sae_token_key));
+               hapd->last_sae_token_key_update = t.sec;
+       }
+
+       buf = wpabuf_alloc(SHA256_MAC_LEN);
+       if (buf == NULL)
+               return NULL;
+
+       token = wpabuf_put(buf, SHA256_MAC_LEN);
+       hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                   addr, ETH_ALEN, token);
+
+       return buf;
+}
+
+
+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 = NULL;
+
+       if (!sta->sae) {
+               if (auth_transaction != 1)
+                       return;
+               sta->sae = os_zalloc(sizeof(*sta->sae));
+               if (sta->sae == NULL)
+                       return;
+               sta->sae->state = SAE_NOTHING;
+       }
+
+       if (auth_transaction == 1) {
+               const u8 *token = NULL;
+               size_t token_len = 0;
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "start SAE authentication (RX commit)");
+               resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
+                                       ((const u8 *) mgmt) + len -
+                                       mgmt->u.auth.variable, &token,
+                                       &token_len, hapd->conf->sae_groups);
+               if (token && check_sae_token(hapd, sta->addr, token, token_len)
+                   < 0) {
+                       wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
+                                  "incorrect token from " MACSTR,
+                                  MAC2STR(sta->addr));
+                       return;
+               }
+
+               if (resp == WLAN_STATUS_SUCCESS) {
+                       if (!token && use_sae_anti_clogging(hapd)) {
+                               wpa_printf(MSG_DEBUG, "SAE: Request anti-"
+                                          "clogging token from " MACSTR,
+                                          MAC2STR(sta->addr));
+                               data = auth_build_token_req(hapd, sta->addr);
+                               resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
+                       } else {
+                               data = auth_process_sae_commit(hapd, sta);
+                               if (data == NULL)
+                                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                               else
+                                       sta->sae->state = SAE_COMMITTED;
+                       }
+               }
+       } else if (auth_transaction == 2) {
+               if (sta->sae->state != SAE_COMMITTED) {
+                       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)");
+               if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
+                                      ((u8 *) mgmt) + len -
+                                      mgmt->u.auth.variable) < 0) {
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               } else {
+                       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);
+
+                       data = auth_build_sae_confirm(hapd, sta);
+                       if (data == NULL)
+                               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       else {
+                               sta->sae->state = SAE_ACCEPTED;
+                               sae_clear_temp_data(sta->sae);
+                       }
+               }
+       } 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;
+
+       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)
 {
@@ -313,10 +545,11 @@ static void handle_auth(struct hostapd_data *hapd,
        const u8 *challenge = NULL;
        u32 session_timeout, acct_interim_interval;
        int vlan_id = 0;
-       u8 psk[PMK_LEN];
-       int has_psk = 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",
@@ -324,6 +557,16 @@ static void handle_auth(struct hostapd_data *hapd,
                return;
        }
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->iconf->ignore_auth_probability > 0.0d &&
+           drand48() < hapd->iconf->ignore_auth_probability) {
+               wpa_printf(MSG_INFO,
+                          "TESTING: ignoring auth frame from " MACSTR,
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        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);
@@ -352,6 +595,10 @@ static void handle_auth(struct hostapd_data *hapd,
              (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",
@@ -360,7 +607,7 @@ static void handle_auth(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!(auth_transaction == 1 ||
+       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);
@@ -378,7 +625,7 @@ static void handle_auth(struct hostapd_data *hapd,
        res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
                                      &session_timeout,
                                      &acct_interim_interval, &vlan_id,
-                                     psk, &has_psk);
+                                     &psk, &identity, &radius_cui);
 
        if (res == HOSTAPD_ACL_REJECT) {
                printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -398,13 +645,12 @@ static void handle_auth(struct hostapd_data *hapd,
 
        sta = ap_sta_add(hapd, mgmt->sa);
        if (!sta) {
-               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
                goto fail;
        }
 
        if (vlan_id > 0) {
-               if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-                                              vlan_id) == NULL) {
+               if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
                        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
                                       "%d received from RADIUS server",
@@ -417,16 +663,19 @@ static void handle_auth(struct hostapd_data *hapd,
                               HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
        }
 
-       if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-               os_free(sta->psk);
-               sta->psk = os_malloc(PMK_LEN);
-               if (sta->psk)
-                       os_memcpy(sta->psk, psk, PMK_LEN);
+       hostapd_free_psk_list(sta->psk);
+       if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+               sta->psk = psk;
+               psk = NULL;
        } else {
-               os_free(sta->psk);
                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);
 
@@ -485,9 +734,18 @@ static void handle_auth(struct hostapd_data *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);
 }
@@ -582,35 +840,20 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
 
-       if (elems->supp_rates_len > sizeof(sta->supported_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",
-                              elems->supp_rates_len);
+                              "Invalid supported rates element length %d+%d",
+                              elems->supp_rates_len,
+                              elems->ext_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;
-       }
+       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;
 }
@@ -654,6 +897,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_IEEE80211N */
 
+#ifdef CONFIG_IEEE80211AC
+       resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
+                                 elems.vht_capabilities_len);
+       if (resp != WLAN_STATUS_SUCCESS)
+               return resp;
+       if (hapd->iconf->ieee80211ac && 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;
@@ -776,8 +1033,18 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                }
 #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) &&
+               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,
@@ -804,6 +1071,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        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;
 }
 
@@ -881,7 +1157,13 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        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);
@@ -953,6 +1235,26 @@ static void handle_assoc(struct hostapd_data *hapd,
                return;
        }
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (reassoc) {
+               if (hapd->iconf->ignore_reassoc_probability > 0.0d &&
+                   drand48() < hapd->iconf->ignore_reassoc_probability) {
+                       wpa_printf(MSG_INFO,
+                                  "TESTING: ignoring reassoc request from "
+                                  MACSTR, MAC2STR(mgmt->sa));
+                       return;
+               }
+       } else {
+               if (hapd->iconf->ignore_assoc_probability > 0.0d &&
+                   drand48() < hapd->iconf->ignore_assoc_probability) {
+                       wpa_printf(MSG_INFO,
+                                  "TESTING: ignoring assoc request from "
+                                  MACSTR, MAC2STR(mgmt->sa));
+                       return;
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        if (reassoc) {
                capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
                listen_interval = le_to_host16(
@@ -1245,13 +1547,32 @@ static int robust_action_frame(u8 category)
 #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)
 {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
        struct sta_info *sta;
        sta = ap_get_sta(hapd, mgmt->sa);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
 
        if (len < IEEE80211_HDRLEN + 1) {
                hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1261,6 +1582,14 @@ static void handle_action(struct hostapd_data *hapd,
                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) &&
@@ -1276,20 +1605,10 @@ static void handle_action(struct hostapd_data *hapd,
        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);
@@ -1299,13 +1618,24 @@ static void handle_action(struct hostapd_data *hapd,
                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;
                }
+               if (hapd->public_action_cb2) {
+                       hapd->public_action_cb2(hapd->public_action_cb2_ctx,
+                                               (u8 *) mgmt, len,
+                                               hapd->iface->freq);
+               }
+               if (hapd->public_action_cb || hapd->public_action_cb2)
+                       return;
                break;
        case WLAN_ACTION_VENDOR_SPECIFIC:
                if (hapd->vendor_action_cb) {
@@ -1342,7 +1672,10 @@ static void handle_action(struct hostapd_data *hapd,
                os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
                resp->u.action.category |= 0x80;
 
-               hostapd_drv_send_mlme(hapd, resp, len, 0);
+               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);
        }
 }
@@ -1398,7 +1731,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 
 
        if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-               handle_probe_req(hapd, mgmt, len);
+               handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
                return;
        }
 
@@ -1493,13 +1826,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        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;
-       }
+       struct ieee80211_vht_capabilities vht_cap;
 
        if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
                                      sizeof(mgmt->u.assoc_resp))) {
@@ -1508,11 +1835,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                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",
@@ -1520,6 +1842,19 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                return;
        }
 
+       if (!ok) {
+               hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "did not acknowledge association response");
+               sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+               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;
 
@@ -1564,11 +1899,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        if (sta->flags & WLAN_STA_HT)
                hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
 #endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+       if (sta->flags & WLAN_STA_VHT)
+               hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
 
        if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
                            sta->supported_rates, sta->supported_rates_len,
                            sta->listen_interval,
                            sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+                           sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
                            sta->flags, sta->qosinfo)) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_NOTICE,
@@ -1744,7 +2084,7 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
                                break;
                }
        }
-       if (sta == NULL)
+       if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
                return;
        if (sta->flags & WLAN_STA_PENDING_POLL) {
                wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
@@ -1774,8 +2114,12 @@ void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
                                break;
                }
        }
-       if (sta == NULL)
+       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);
 }
@@ -1814,6 +2158,9 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 
        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)",
index 43042a5..2aab56d 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / IEEE 802.11 Management
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_11_H
@@ -51,15 +45,22 @@ 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);
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+                          struct ieee80211_vht_capabilities *vht_cap,
+                          struct ieee80211_vht_capabilities *neg_vht_cap);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *ht_capab, size_t ht_capab_len);
 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,
@@ -78,5 +79,6 @@ 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 */
index f3f313d..c311e55 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
@@ -28,6 +22,7 @@
 #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
@@ -41,8 +36,9 @@ struct hostapd_cached_radius_acl {
        u32 session_timeout;
        u32 acct_interim_interval;
        int vlan_id;
-       int has_psk;
-       u8 psk[PMK_LEN];
+       struct hostapd_sta_wpa_psk_short *psk;
+       char *identity;
+       char *radius_cui;
 };
 
 
@@ -57,6 +53,15 @@ struct hostapd_acl_query_data {
 
 
 #ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
+{
+       os_free(e->identity);
+       os_free(e->radius_cui);
+       hostapd_free_psk_list(e->psk);
+       os_free(e);
+}
+
+
 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
 {
        struct hostapd_cached_radius_acl *prev;
@@ -64,43 +69,73 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
        while (acl_cache) {
                prev = acl_cache;
                acl_cache = acl_cache->next;
-               os_free(prev);
+               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,
-                                u8 *psk, int *has_psk)
+                                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);
-       entry = hapd->acl_cache;
 
-       while (entry) {
-               if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-                       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;
-                       if (psk)
-                               os_memcpy(psk, entry->psk, PMK_LEN);
-                       if (has_psk)
-                               *has_psk = entry->has_psk;
-                       return entry->accepted;
-               }
+       for (entry = hapd->acl_cache; entry; entry = entry->next) {
+               if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
+                       continue;
 
-               entry = entry->next;
+               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;
@@ -146,37 +181,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
                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");
+       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 ":%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));
@@ -186,12 +193,6 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
                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))) {
@@ -199,7 +200,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
                goto fail;
        }
 
-       radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
+       if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+               goto fail;
        return 0;
 
  fail:
@@ -218,14 +220,19 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
  * @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: Buffer for returning WPA PSK
- * @has_psk: Buffer for indicating whether psk was filled
+ * @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,
-                           u8 *psk, int *has_psk)
+                           struct hostapd_sta_wpa_psk_short **psk,
+                           char **identity, char **radius_cui)
 {
        if (session_timeout)
                *session_timeout = 0;
@@ -233,10 +240,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                *acct_interim_interval = 0;
        if (vlan_id)
                *vlan_id = 0;
-       if (has_psk)
-               *has_psk = 0;
        if (psk)
-               os_memset(psk, 0, PMK_LEN);
+               *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))
@@ -261,7 +270,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                /* 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, has_psk);
+                                               vlan_id, psk,
+                                               identity, radius_cui);
                if (res == HOSTAPD_ACL_ACCEPT ||
                    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
                        return res;
@@ -273,6 +283,14 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                        if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
                                /* pending query in RADIUS retransmit queue;
                                 * do not generate a new one */
+                               if (identity) {
+                                       os_free(*identity);
+                                       *identity = NULL;
+                               }
+                               if (radius_cui) {
+                                       os_free(*radius_cui);
+                                       *radius_cui = NULL;
+                               }
                                return HOSTAPD_ACL_PENDING;
                        }
                        query = query->next;
@@ -338,7 +356,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
                        hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
                        tmp = entry;
                        entry = entry->next;
-                       os_free(tmp);
+                       hostapd_acl_cache_free_entry(tmp);
                        continue;
                }
 
@@ -395,6 +413,54 @@ static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+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
@@ -453,8 +519,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        cache->timestamp = t.sec;
        os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
        if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
-               int passphraselen;
-               char *passphrase;
+               u8 *buf;
+               size_t len;
 
                if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
                                              &cache->session_timeout) == 0)
@@ -475,30 +541,25 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 
                cache->vlan_id = radius_msg_get_vlanid(msg);
 
-               passphrase = radius_msg_get_tunnel_password(
-                       msg, &passphraselen,
-                       hapd->conf->radius->auth_server->shared_secret,
-                       hapd->conf->radius->auth_server->shared_secret_len,
-                       req);
-               cache->has_psk = passphrase != NULL;
-               if (passphrase != NULL) {
-                       /* passphrase does not contain the NULL termination.
-                        * Add it here as pbkdf2_sha1 requires it. */
-                       char *strpassphrase = os_zalloc(passphraselen + 1);
-                       if (strpassphrase) {
-                               os_memcpy(strpassphrase, passphrase,
-                                         passphraselen);
-                               pbkdf2_sha1(strpassphrase,
-                                           hapd->conf->ssid.ssid,
-                                           hapd->conf->ssid.ssid_len, 4096,
-                                           cache->psk, PMK_LEN);
-                               os_free(strpassphrase);
-                       }
-                       os_free(passphrase);
+               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 == NULL)
+                   !cache->psk)
                        cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
@@ -570,3 +631,13 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
                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);
+       }
+}
index a90571f..2bc1065 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / IEEE 802.11 authentication (ACL)
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_11_AUTH_H
@@ -25,8 +19,10 @@ enum {
 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,
-                           u8 *psk, int *has_psk);
+                           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 */
index 6c3696f..6483e1c 100644 (file)
@@ -133,8 +133,7 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
        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)
+       else if (iface->conf->secondary_channel && 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;
index 8503fce..c36bbe3 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -170,41 +164,89 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
 #endif /* CONFIG_IEEE80211W */
 
 
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+       *pos = 0x00;
+
+       switch (idx) {
+       case 0: /* Bits 0-7 */
+               break;
+       case 1: /* Bits 8-15 */
+               break;
+       case 2: /* Bits 16-23 */
+               if (hapd->conf->wnm_sleep_mode)
+                       *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+               if (hapd->conf->bss_transition)
+                       *pos |= 0x08; /* Bit 19 - BSS Transition */
+               break;
+       case 3: /* Bits 24-31 */
+#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 */
+               break;
+       case 4: /* Bits 32-39 */
+               if (hapd->conf->tdls & TDLS_PROHIBIT)
+                       *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+               if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+                       /* Bit 39 - TDLS Channel Switching Prohibited */
+                       *pos |= 0x80;
+               }
+               break;
+       case 5: /* Bits 40-47 */
+               break;
+       case 6: /* Bits 48-55 */
+               if (hapd->conf->ssid.utf8_ssid)
+                       *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+               break;
+       }
+}
+
+
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
 {
        u8 *pos = eid;
-       u8 len = 0;
+       u8 len = 0, i;
 
        if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
                len = 5;
        if (len < 4 && hapd->conf->interworking)
                len = 4;
+       if (len < 3 && hapd->conf->wnm_sleep_mode)
+               len = 3;
+       if (len < 7 && hapd->conf->ssid.utf8_ssid)
+               len = 7;
+#ifdef CONFIG_WNM
+       if (len < 4)
+               len = 4;
+#endif /* CONFIG_WNM */
+       if (len < hapd->iface->extended_capa_len)
+               len = hapd->iface->extended_capa_len;
        if (len == 0)
                return eid;
 
        *pos++ = WLAN_EID_EXT_CAPAB;
        *pos++ = len;
-       *pos++ = 0x00;
-       *pos++ = 0x00;
-       *pos++ = 0x00;
+       for (i = 0; i < len; i++, pos++) {
+               hostapd_ext_capab_byte(hapd, pos, i);
 
-       *pos = 0x00;
-       if (hapd->conf->time_advertisement == 2)
-               *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
-       if (hapd->conf->interworking)
-               *pos |= 0x80; /* Bit 31 - Interworking */
-       pos++;
+               if (i < hapd->iface->extended_capa_len) {
+                       *pos &= ~hapd->iface->extended_capa_mask[i];
+                       *pos |= hapd->iface->extended_capa[i];
+               }
+       }
 
-       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++;
+       while (len > 0 && eid[1 + len] == 0) {
+               len--;
+               eid[1] = len;
+       }
+       if (len == 0)
+               return eid;
 
-       return pos;
+       return eid + 2 + len;
 }
 
 
@@ -403,3 +445,31 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
 
        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;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
new file mode 100644 (file)
index 0000000..0012c0f
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@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;
+}
+
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+                          struct ieee80211_vht_capabilities *vht_cap,
+                          struct ieee80211_vht_capabilities *neg_vht_cap)
+{
+       if (vht_cap == NULL)
+               return;
+       os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
+
+       /* TODO: mask own capabilities, like get_ht_capab() */
+}
index 153b271..82ea9a6 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -72,8 +66,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
        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, sta->flags);
+               hostapd_drv_hapd_send_eapol(
+                       hapd, sta->addr, buf, len,
+                       encrypt, hostapd_sta_flags_to_drv(sta->flags));
        }
 
        os_free(buf);
@@ -105,8 +100,10 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
                       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
        }
 
-       if (authorized)
+       if (authorized) {
+               os_get_time(&sta->connected_time);
                accounting_sta_start(hapd, sta);
+       }
 }
 
 
@@ -132,7 +129,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
        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_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))) {
@@ -358,6 +355,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 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:
@@ -400,27 +399,155 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
 
        /* Save station identity for future RADIUS packets */
        os_free(sm->identity);
-       sm->identity = os_malloc(identity_len + 1);
+       sm->identity = (u8 *) dup_binstr(identity, identity_len);
        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;
-       char buf[128];
        struct eapol_state_machine *sm = sta->eapol_sm;
 
        if (sm == NULL)
@@ -448,83 +575,20 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                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");
+       if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
+                                  msg) < 0)
                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)) {
+       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 (!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;
@@ -547,6 +611,25 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                }
        }
 
+       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;
 
@@ -652,7 +735,8 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
                        flags |= EAPOL_SM_FROM_PMKSA_CACHE;
        }
        return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
-                               sta->wps_ie, sta->p2p_ie, sta);
+                               sta->wps_ie, sta->p2p_ie, sta,
+                               sta->identity, sta->radius_cui);
 }
 
 
@@ -867,12 +951,22 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
        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;
        }
 
@@ -918,6 +1012,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                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 */
@@ -939,6 +1034,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                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;
@@ -972,6 +1068,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
 #ifndef CONFIG_NO_RADIUS
        radius_msg_free(sm->last_recv_radius);
        radius_free_class(&sm->radius_class);
+       wpabuf_free(sm->radius_cui);
 #endif /* CONFIG_NO_RADIUS */
 
        os_free(sm->identity);
@@ -983,9 +1080,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
 static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
                                          struct sta_info *sta)
 {
-       u8 *eap;
-       size_t len;
-       struct eap_hdr *hdr;
+       struct wpabuf *eap;
+       const struct eap_hdr *hdr;
        int eap_type = -1;
        char buf[64];
        struct radius_msg *msg;
@@ -999,7 +1095,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
 
        msg = sm->last_recv_radius;
 
-       eap = radius_msg_get_eap(msg, &len);
+       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
@@ -1011,19 +1107,19 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
                return;
        }
 
-       if (len < sizeof(*hdr)) {
+       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");
-               os_free(eap);
+               wpabuf_free(eap);
                sm->eap_if->aaaEapNoReq = TRUE;
                return;
        }
 
-       if (len > sizeof(*hdr))
-               eap_type = eap[sizeof(*hdr)];
+       if (wpabuf_len(eap) > sizeof(*hdr))
+               eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
 
-       hdr = (struct eap_hdr *) eap;
+       hdr = wpabuf_head(eap);
        switch (hdr->code) {
        case EAP_CODE_REQUEST:
                if (eap_type >= 0)
@@ -1058,7 +1154,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
        sm->eap_if->aaaEapReq = TRUE;
 
        wpabuf_free(sm->eap_if->aaaEapReqData);
-       sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
+       sm->eap_if->aaaEapReqData = eap;
 }
 
 
@@ -1123,7 +1219,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
        if (count <= 0)
                return;
 
-       nclass = os_zalloc(count * sizeof(struct radius_attr_data));
+       nclass = os_calloc(count, sizeof(struct radius_attr_data));
        if (nclass == NULL)
                return;
 
@@ -1174,13 +1270,10 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
                                    NULL) < 0)
                return;
 
-       identity = os_malloc(len + 1);
+       identity = (u8 *) dup_binstr(buf, len);
        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'",
@@ -1193,6 +1286,32 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
 }
 
 
+/* 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;
@@ -1319,8 +1438,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                        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_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO,
@@ -1352,6 +1470,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                                    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 ?
@@ -1574,8 +1693,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
        const struct hostapd_eap_user *eap_user;
        int i;
 
-       eap_user = hostapd_get_eap_user(hapd->conf, identity,
-                                       identity_len, phase2);
+       eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
        if (eap_user == NULL)
                return -1;
 
@@ -1869,6 +1987,14 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 }
 
 
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+       if (sm == NULL)
+               return NULL;
+       return sm->radius_cui;
+}
+
+
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
 {
        *len = 0;
@@ -2085,7 +2211,24 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                               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);
+       }
+#else /* CONFIG_WPS */
        if (!success) {
                /*
                 * Many devices require deauthentication after WPS provisioning
@@ -2107,4 +2250,5 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                ap_sta_disconnect(hapd, sta, sta->addr,
                                  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
        }
+#endif
 }
index 267e22a..e1df940 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_1X_H
@@ -20,38 +14,8 @@ 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 */
+struct hostapd_radius_attr;
+struct radius_msg;
 
 
 void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
@@ -73,6 +37,7 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 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);
@@ -88,4 +53,9 @@ 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 */
index 6f8b778..795d313 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / P2P integration
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index 95b31d9..0e3921c 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / P2P integration
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef P2P_HOSTAPD_H
index b8fa5a9..ba5c606 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - PeerKey for Direct Link Setup (DLS)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index 22f44b7..40972e9 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -46,6 +40,7 @@ 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 */
@@ -53,8 +48,8 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 }
 
 
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
-                                  struct rsn_pmksa_cache_entry *entry)
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+                           struct rsn_pmksa_cache_entry *entry)
 {
        struct rsn_pmksa_cache_entry *pos, *prev;
 
@@ -100,11 +95,9 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 
        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);
+                          MACSTR, MAC2STR(pmksa->pmksa->spa));
+               pmksa_cache_free_entry(pmksa, pmksa->pmksa);
        }
 
        pmksa_cache_set_expiration(pmksa);
@@ -142,6 +135,9 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
                }
        }
 
+       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 */
@@ -169,6 +165,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
                                  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);
@@ -208,6 +209,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
        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);
@@ -305,6 +308,8 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
                                  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 */
index 9628b13..aa90024 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PMKSA_CACHE_H
@@ -31,6 +25,7 @@ struct rsn_pmksa_cache_entry {
 
        u8 *identity;
        size_t identity_len;
+       struct wpabuf *cui;
        struct radius_class_data radius_class;
        u8 eap_type_authsrv;
        int vlan_id;
@@ -60,5 +55,7 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
                    const u8 *aa, const u8 *pmkid);
 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
                               struct eapol_state_machine *eapol);
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+                           struct rsn_pmksa_cache_entry *entry);
 
 #endif /* PMKSA_CACHE_H */
index 8e13315..3e0c800 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index 5348bee..69fb356 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PREAUTH_H
index d9c348e..833f1b2 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / Station table
  * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -18,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
+#include "common/sae.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "drivers/driver.h"
@@ -26,6 +21,7 @@
 #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"
@@ -34,6 +30,7 @@
 #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,
@@ -200,6 +197,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        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);
@@ -224,11 +223,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        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);
-       os_free(sta->psk);
+       hostapd_free_psk_list(sta->psk);
+       os_free(sta->identity);
+       os_free(sta->radius_cui);
+
+#ifdef CONFIG_SAE
+       sae_clear_data(sta->sae);
+       os_free(sta->sae);
+#endif /* CONFIG_SAE */
 
        os_free(sta);
 }
@@ -267,7 +283,11 @@ 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;
+       int reason;
 
+       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 "
@@ -280,12 +300,24 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
            (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 rom kernel driver for "
+                               "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 */
@@ -293,7 +325,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                                "Station " MACSTR " has been active %is ago",
                                MAC2STR(sta->addr), inactive_sec);
                        sta->timeout_next = STA_NULLFUNC;
-                       next_time = hapd->conf->ap_max_inactivity -
+                       next_time = hapd->conf->ap_max_inactivity + fuzz -
                                inactive_sec;
                } else {
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -301,12 +333,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                                "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)) {
+           !(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
@@ -316,6 +352,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        }
 
        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;
@@ -340,19 +379,25 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                                hapd, sta->addr,
                                WLAN_REASON_PREV_AUTH_NOT_VALID);
                } else {
-                       hostapd_drv_sta_disassoc(
-                               hapd, sta->addr,
-                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+                       reason = (sta->timeout_next == STA_DISASSOC) ?
+                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+                               WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+                       hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
                }
        }
 
        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:
+       case STA_DISASSOC_FROM_CLI:
                ap_sta_set_authorized(hapd, sta, 0);
                sta->flags &= ~WLAN_STA_ASSOC;
                ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -364,11 +409,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_INFO, "disassociated due to "
                               "inactivity");
+               reason = (sta->timeout_next == STA_DISASSOC) ?
+                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+                       WLAN_REASON_PREV_AUTH_NOT_VALID;
                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);
+               mlme_disassociate_indication(hapd, sta, reason);
                break;
        case STA_DEAUTH:
        case STA_REMOVE:
@@ -393,8 +443,14 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
        struct sta_info *sta = timeout_ctx;
        u8 addr[ETH_ALEN];
 
-       if (!(sta->flags & WLAN_STA_AUTH))
+       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);
@@ -449,8 +505,13 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
                return NULL;
        }
        sta->acct_interim_interval = hapd->conf->acct_interim_interval;
+       accounting_sta_get_id(hapd, sta);
 
        /* 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);
@@ -521,9 +582,14 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
 {
        wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
                   hapd->conf->iface, MAC2STR(sta->addr));
-       sta->flags &= ~WLAN_STA_ASSOC;
+       sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
        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);
@@ -557,6 +623,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
        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);
@@ -572,6 +643,23 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *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)
 {
@@ -724,8 +812,9 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
            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);
+       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) {
@@ -747,9 +836,7 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
                       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 */
 }
 
 
@@ -774,57 +861,52 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
                           int authorized)
 {
        const u8 *dev_addr = NULL;
+       char buf[100];
+#ifdef CONFIG_P2P
+       u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
        if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
                return;
 
 #ifdef CONFIG_P2P
-       dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+       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 (dev_addr)
+               os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
+                           MAC2STR(sta->addr), MAC2STR(dev_addr));
+       else
+               os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
+
        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));
+               wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s", buf);
+
                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));
+                   hapd->msg_ctx_parent != hapd->msg_ctx)
+                       wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+                                         AP_STA_CONNECTED "%s", buf);
 
                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));
+               wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
+
                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));
+                   hapd->msg_ctx_parent != hapd->msg_ctx)
+                       wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+                                         AP_STA_DISCONNECTED "%s", buf);
+
                sta->flags &= ~WLAN_STA_AUTHORIZED;
        }
 
        if (hapd->sta_authorized_cb)
                hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
-                                       sta->addr, authorized);
+                                       sta->addr, authorized, dev_addr);
 }
 
 
@@ -841,7 +923,14 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
        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);
index daa96bf..f8f5a83 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / Station table
  * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef STA_INFO_H
@@ -33,6 +27,8 @@
 #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)
@@ -66,7 +62,8 @@ struct sta_info {
        u8 previous_ap[6];
 
        enum {
-               STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+               STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE,
+               STA_DISASSOC_FROM_CLI
        } timeout_next;
 
        u16 deauth_reason;
@@ -99,9 +96,14 @@ struct sta_info {
        struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
 
        int vlan_id;
-       u8 *psk; /* PSK from RADIUS authentication server */
+        /* 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;
@@ -113,8 +115,21 @@ struct sta_info {
        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
+       struct sae_data *sae;
+#endif /* CONFIG_SAE */
 };
 
 
@@ -143,7 +158,6 @@ int ap_for_each_sta(struct hostapd_data *hapd,
 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,
@@ -155,6 +169,10 @@ 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);
index fac7f4b..4a2ea06 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -17,6 +11,7 @@
 #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"
@@ -50,12 +45,17 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
        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) {
+       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_sta_set_authorized(hapd, sta, 0);
-               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-               hostapd_drv_sta_remove(hapd, sta->addr);
+               ap_free_sta(hapd, sta);
        }
 }
 
@@ -66,9 +66,10 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
 }
 
 
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+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);
@@ -84,7 +85,7 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
                                   "MLME-MICHAELMICFAILURE.indication "
                                   "for not associated STA (" MACSTR
                                   ") ignored", MAC2STR(addr));
-                       return;
+                       return ret;
                }
        }
 
@@ -93,8 +94,12 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
                hapd->michael_mic_failures = 1;
        } else {
                hapd->michael_mic_failures++;
-               if (hapd->michael_mic_failures > 1)
+               if (hapd->michael_mic_failures > 1) {
                        ieee80211_tkip_countermeasures_start(hapd);
+                       ret = 1;
+               }
        }
        hapd->michael_mic_failure = now.sec;
+
+       return ret;
 }
index a8ffd16..d3eaed3 100644 (file)
@@ -1,21 +1,15 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TKIP_COUNTERMEASURES_H
 #define TKIP_COUNTERMEASURES_H
 
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+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 */
index 09bc32f..931968c 100644 (file)
@@ -2,14 +2,8 @@
  * AP mode helper functions
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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),
+                                          const u8 *ie, size_t ie_len,
+                                          int ssi_signal),
                                 void *ctx)
 {
        struct hostapd_probereq_cb *n;
 
-       n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
-                      sizeof(struct hostapd_probereq_cb));
+       n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
+                            sizeof(struct hostapd_probereq_cb));
        if (n == NULL)
                return -1;
 
@@ -83,7 +78,8 @@ 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);
+       if (hapd->iface->interfaces &&
+           hapd->iface->interfaces->for_each_interface)
+               hapd->iface->interfaces->for_each_interface(
+                       hapd->iface->interfaces, prune_associations, &data);
 }
index f2f766f..70affda 100644 (file)
@@ -21,6 +21,7 @@
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "vlan_init.h"
+#include "vlan_util.h"
 
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -335,7 +336,9 @@ static int br_getnumports(const char *br_name)
 }
 
 
-static int vlan_rem(const char *if_name)
+#ifndef CONFIG_VLAN_NETLINK
+
+int vlan_rem(const char *if_name)
 {
        int fd;
        struct vlan_ioctl_args if_request;
@@ -378,7 +381,7 @@ static int vlan_rem(const char *if_name)
        returns 1 if the interface already exists
        returns 0 otherwise
 */
-static int vlan_add(const char *if_name, int vid)
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
 {
        int fd;
        struct vlan_ioctl_args if_request;
@@ -474,6 +477,125 @@ static int vlan_set_name_type(unsigned int name_type)
        return 0;
 }
 
+#endif /* CONFIG_VLAN_NETLINK */
+
+
+/**
+ * Increase the usage counter for given parent/ifname combination.
+ * If create is set, then this iface is added to the global list.
+ * Returns
+ *     -1 on error
+ *     0 if iface is not in list
+ *     1 if iface is in list (was there or has been added)
+ */
+static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
+                                 int create, struct hostapd_data *hapd)
+{
+       size_t i;
+       struct hostapd_dynamic_iface *j = NULL, **tmp;
+       struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
+
+       if (!parent)
+               parent = "";
+
+       for (i = 0; i < hapd_global->count_dynamic; i++) {
+               j = hapd_global->dynamic_iface[i];
+               if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+                   os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+                       break;
+       }
+       if (i < hapd_global->count_dynamic) {
+               j->usage++;
+               return 1;
+       }
+
+       /* new entry required */
+       if (!create)
+               return 0;
+
+       j = os_zalloc(sizeof(*j));
+       if (!j)
+               return -1;
+       os_strlcpy(j->iface, ifname, sizeof(j->iface));
+       os_strlcpy(j->parent, parent, sizeof(j->parent));
+
+       tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
+                              sizeof(*hapd_global->dynamic_iface));
+       if (!tmp) {
+               wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
+                          __func__);
+               return -1;
+       }
+       hapd_global->count_dynamic++;
+       hapd_global->dynamic_iface = tmp;
+       hapd_global->dynamic_iface[i] = j;
+
+       return 1;
+}
+
+
+/**
+ * Decrease the usage counter for given ifname.
+ * Returns
+ *     -1 on error or if iface was not found
+ *     0 if iface was found and is still present
+ *     1 if iface was removed from global list
+ */
+static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
+                                 struct hostapd_data *hapd)
+{
+       size_t i;
+       struct hostapd_dynamic_iface *j = NULL, **tmp;
+       struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
+
+       if (!parent)
+               parent = "";
+
+       for (i = 0; i < hapd_glob->count_dynamic; i++) {
+               j = hapd_glob->dynamic_iface[i];
+               if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+                   os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+                       break;
+       }
+
+       if (i == hapd_glob->count_dynamic) {
+               /*
+                * Interface not in global list. This can happen if alloc in
+                * _get_ failed.
+                */
+               return -1;
+       }
+
+       if (j->usage > 0) {
+               j->usage--;
+               return 0;
+       }
+
+       os_free(j);
+       for (; i < hapd_glob->count_dynamic - 1; i++)
+               hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
+       hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
+       hapd_glob->count_dynamic--;
+
+       if (hapd_glob->count_dynamic == 0) {
+               os_free(hapd_glob->dynamic_iface);
+               hapd_glob->dynamic_iface = NULL;
+               return 1;
+       }
+
+       tmp = os_realloc_array(hapd_glob->dynamic_iface,
+                              hapd_glob->count_dynamic,
+                              sizeof(*hapd_glob->dynamic_iface));
+       if (!tmp) {
+               wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
+                          __func__);
+               return -1;
+       }
+       hapd_glob->dynamic_iface = tmp;
+
+       return 1;
+}
+
 
 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
@@ -481,35 +603,65 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
        char br_name[IFNAMSIZ];
        struct hostapd_vlan *vlan = hapd->conf->vlan;
        char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+       int vlan_naming = hapd->conf->ssid.vlan_naming;
+       int ret;
 
        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 (hapd->conf->vlan_bridge[0]) {
+                               os_snprintf(br_name, sizeof(br_name), "%s%d",
+                                           hapd->conf->vlan_bridge,
+                                           vlan->vlan_id);
+                       } else if (tagged_interface) {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "br%s.%d", tagged_interface,
+                                           vlan->vlan_id);
+                       } else {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "brvlan%d", vlan->vlan_id);
+                       }
 
-                       if (!br_addbr(br_name))
+                       ret = br_addbr(br_name);
+                       if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
+                                                  hapd))
                                vlan->clean |= DVLAN_CLEAN_BR;
 
                        ifconfig_up(br_name);
 
                        if (tagged_interface) {
-
-                               if (!vlan_add(tagged_interface, vlan->vlan_id))
+                               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);
+                               ret = vlan_add(tagged_interface, vlan->vlan_id,
+                                             vlan_ifname);
+                               if (hapd_get_dynamic_iface(NULL, vlan_ifname,
+                                                          ret == 0, hapd))
                                        vlan->clean |= DVLAN_CLEAN_VLAN;
 
-                               os_snprintf(vlan_ifname, sizeof(vlan_ifname),
-                                           "vlan%d", vlan->vlan_id);
-
-                               if (!br_addif(br_name, vlan_ifname))
+                               ret = br_addif(br_name, vlan_ifname);
+                               if (hapd_get_dynamic_iface(br_name,
+                                                          vlan_ifname,
+                                                          ret == 0, hapd))
                                        vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
 
                                ifconfig_up(vlan_ifname);
                        }
 
-                       if (!br_addif(br_name, ifname))
+                       ret = br_addif(br_name, ifname);
+                       if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
+                                                  hapd))
                                vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
 
                        ifconfig_up(ifname);
@@ -527,6 +679,7 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
        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);
 
@@ -534,24 +687,48 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 
        while (vlan) {
                if (os_strcmp(ifname, vlan->ifname) == 0) {
-                       os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-                                   vlan->vlan_id);
+                       if (hapd->conf->vlan_bridge[0]) {
+                               os_snprintf(br_name, sizeof(br_name), "%s%d",
+                                           hapd->conf->vlan_bridge,
+                                           vlan->vlan_id);
+                       } else if (tagged_interface) {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "br%s.%d", tagged_interface,
+                                           vlan->vlan_id);
+                       } else {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "brvlan%d", vlan->vlan_id);
+                       }
 
-                       if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+                       if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
+                           hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
                                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)
+                               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) &&
+                                   hapd_put_dynamic_iface(br_name, vlan_ifname,
+                                                          hapd))
                                        br_delif(br_name, vlan_ifname);
                                ifconfig_down(vlan_ifname);
 
-                               if (vlan->clean & DVLAN_CLEAN_VLAN)
+                               if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
+                                   hapd_put_dynamic_iface(NULL, vlan_ifname,
+                                                          hapd))
                                        vlan_rem(vlan_ifname);
                        }
 
                        if ((vlan->clean & DVLAN_CLEAN_BR) &&
+                           hapd_put_dynamic_iface(NULL, br_name, hapd) &&
                            br_getnumports(br_name) == 0) {
                                ifconfig_down(br_name);
                                br_delbr(br_name);
@@ -682,7 +859,12 @@ full_dynamic_vlan_init(struct hostapd_data *hapd)
        if (priv == NULL)
                return NULL;
 
-       vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#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) {
@@ -808,6 +990,27 @@ int vlan_init(struct hostapd_data *hapd)
        hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
+       if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+           !hapd->conf->vlan) {
+               /* dynamic vlans enabled but no (or empty) vlan_file given */
+               struct hostapd_vlan *vlan;
+               vlan = os_zalloc(sizeof(*vlan));
+               if (vlan == NULL) {
+                       wpa_printf(MSG_ERROR, "Out of memory while assigning "
+                                  "VLAN interfaces");
+                       return -1;
+               }
+
+               vlan->vlan_id = VLAN_ID_WILDCARD;
+               os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+                           hapd->conf->iface);
+               if (hapd->conf->vlan_tail)
+                       hapd->conf->vlan_tail->next = vlan;
+               else
+                       hapd->conf->vlan = vlan;
+               hapd->conf->vlan_tail = vlan;
+       }
+
        if (vlan_dynamic_add(hapd, hapd->conf->vlan))
                return -1;
 
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
new file mode 100644 (file)
index 0000000..cc54051
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@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;
+}
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
new file mode 100644 (file)
index 0000000..bef5a16
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@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 */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
new file mode 100644 (file)
index 0000000..54a6b85
--- /dev/null
@@ -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;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
new file mode 100644 (file)
index 0000000..f05726e
--- /dev/null
@@ -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 */
index 1b5a5a2..83cc857 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -52,6 +46,7 @@ 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;
@@ -59,11 +54,12 @@ static const int dot11RSNAConfigPMKReauthThreshold = 70;
 static const int dot11RSNAConfigSATimeout = 60;
 
 
-static inline void wpa_auth_mic_failure_report(
+static inline int 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);
+               return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+       return 0;
 }
 
 
@@ -283,30 +279,12 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *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 int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
                                          struct wpa_group *group)
 {
-       u8 buf[ETH_ALEN + 8 + sizeof(group)];
+       u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
        u8 rkey[32];
+       unsigned long ptr;
 
        if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
                return -1;
@@ -318,7 +296,8 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
         */
        os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
        wpa_get_ntp_timestamp(buf + ETH_ALEN);
-       os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+       ptr = (unsigned long) group;
+       os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
        if (random_get_bytes(rkey, sizeof(rkey)) < 0)
                return -1;
 
@@ -343,8 +322,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
 
        group->GTKAuthenticator = TRUE;
        group->vlan_id = vlan_id;
-
-       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+       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 "
@@ -519,7 +497,7 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
         * configuration.
         */
        group = wpa_auth->group;
-       wpa_group_set_key_len(group, wpa_auth->conf.wpa_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;
@@ -646,14 +624,14 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 }
 
 
-static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
+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 (!sm->key_replay[i].valid)
+               if (!ctr[i].valid)
                        break;
-               if (os_memcmp(replay_counter, sm->key_replay[i].counter,
+               if (os_memcmp(replay_counter, ctr[i].counter,
                              WPA_REPLAY_COUNTER_LEN) == 0)
                        return 1;
        }
@@ -661,6 +639,20 @@ static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
 }
 
 
+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,
@@ -711,8 +703,8 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_IEEE80211R */
 
 
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
-                                    struct wpa_state_machine *sm, int group)
+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,
@@ -729,7 +721,8 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
                                "ignore Michael MIC failure report since "
                                "pairwise cipher is not TKIP");
        } else {
-               wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+               if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+                       return 1; /* STA entry was removed */
                sm->dot11RSNAStatsTKIPRemoteMICFailures++;
                wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
        }
@@ -739,6 +732,7 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
         * Authenticator may do it, let's change the keys now anyway.
         */
        wpa_request_new_ptk(sm);
+       return 0;
 }
 
 
@@ -780,7 +774,14 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        }
 
        if (sm->wpa == WPA_VERSION_WPA2) {
-               if (key->type != EAPOL_KEY_TYPE_RSN) {
+               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);
@@ -833,7 +834,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        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 (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,
@@ -849,7 +851,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                                wpa_auth_logger(wpa_auth, sm->addr,
                                                LOGGER_WARNING,
                                                "did not use HMAC-SHA1-AES "
-                                               "with CCMP");
+                                               "with CCMP/GCMP");
                                return;
                        }
                }
@@ -867,11 +869,44 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        }
 
        if (!(key_info & WPA_KEY_INFO_REQUEST) &&
-           !wpa_replay_counter_valid(sm, key->replay_counter)) {
+           !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
                int i;
-               wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-                                "received EAPOL-Key %s with unexpected "
-                                "replay counter", msgtxt);
+
+               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;
@@ -884,10 +919,13 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                return;
        }
 
+continue_processing:
        switch (msg) {
        case PAIRWISE_2:
                if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
-                   sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) {
+                   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",
@@ -908,9 +946,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                        wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
                                   "collect more entropy for random number "
                                   "generation");
-                       sm->group->reject_4way_hs_for_entropy = FALSE;
                        random_mark_pool_ready();
-                       sm->group->first_sta_seen = FALSE;
                        wpa_sta_disconnect(wpa_auth, sm->addr);
                        return;
                }
@@ -1016,7 +1052,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        }
 
        sm->MICVerified = FALSE;
-       if (sm->PTK_valid) {
+       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");
@@ -1050,9 +1086,10 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_PEERKEY */
                        return;
                } else if (key_info & WPA_KEY_INFO_ERROR) {
-                       wpa_receive_error_report(
-                               wpa_auth, sm,
-                               !(key_info & WPA_KEY_INFO_KEY_TYPE));
+                       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 "
@@ -1070,19 +1107,34 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                        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;
+               /* 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
@@ -1175,12 +1227,12 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                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)
+       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;
+       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 "
@@ -1222,20 +1274,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        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;
-       }
+       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);
 
@@ -1308,6 +1347,16 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                }
                wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
                                  key->key_mic);
+#ifdef CONFIG_TESTING_OPTIONS
+               if (!pairwise &&
+                   wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+                   drand48() <
+                   wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                                       "Corrupting group EAPOL-Key Key MIC");
+                       key->key_mic[0]++;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
        }
 
        wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
@@ -1336,7 +1385,8 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
 
        ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
        if (ctr == 1 && wpa_auth->conf.tx_status)
-               timeout_ms = eapol_key_timeout_first;
+               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))
@@ -1467,22 +1517,6 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 }
 
 
-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);
@@ -1540,9 +1574,11 @@ SM_STATE(WPA_PTK, AUTHENTICATION)
 }
 
 
-static void wpa_group_first_station(struct wpa_authenticator *wpa_auth,
-                                   struct wpa_group *group)
+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
@@ -1556,7 +1592,11 @@ static void wpa_group_first_station(struct wpa_authenticator *wpa_auth,
                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);
@@ -1567,16 +1607,26 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
 {
        SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
 
-       if (!sm->group->first_sta_seen) {
-               wpa_group_first_station(sm->wpa_auth, sm->group);
-               sm->group->first_sta_seen = TRUE;
-       }
+       wpa_group_ensure_init(sm->wpa_auth, sm->group);
+       sm->ReAuthenticationRequest = FALSE;
 
-       os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+       /*
+        * 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.");
+               sm->Disconnect = TRUE;
+               return;
+       }
        wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
                    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
@@ -1691,7 +1741,7 @@ SM_STATE(WPA_PTK, PTKSTART)
 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;
+       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);
@@ -1714,6 +1764,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 
        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
@@ -1815,6 +1866,14 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
            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);
 
@@ -1839,7 +1898,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+       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;
@@ -1877,6 +1936,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                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;
@@ -1988,15 +2056,8 @@ 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;
-               }
+               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);
@@ -2133,8 +2194,10 @@ SM_STEP(WPA_PTK)
                SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
                break;
        case WPA_PTK_PTKINITNEGOTIATING:
-               if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
-                   sm->EAPOLKeyPairwise && sm->MICVerified)
+               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) {
@@ -2171,6 +2234,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        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);
 
@@ -2191,6 +2255,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        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);
@@ -2202,10 +2276,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
                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);
+                                 gtk, gsm->GTK_len);
                pos = ieee80211w_kde_add(sm, pos);
        } else {
-               kde = gsm->GTK[gsm->GN - 1];
+               kde = gtk;
                pos = kde + gsm->GTK_len;
        }
 
@@ -2331,6 +2405,9 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
 
 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");
@@ -2348,6 +2425,10 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
                                "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;
 
@@ -2356,6 +2437,86 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 }
 
 
+#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)
 {
@@ -2385,7 +2546,7 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
                           group->GKeyDoneStations);
                group->GKeyDoneStations = 0;
        }
-       wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+       wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
        wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
                   group->GKeyDoneStations);
 }
@@ -2397,7 +2558,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
        int ret = 0;
 
        if (wpa_auth_set_key(wpa_auth, group->vlan_id,
-                            wpa_alg_enum(wpa_auth->conf.wpa_group),
+                            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;
@@ -2537,23 +2698,6 @@ static const char * wpa_bool_txt(int bool)
 }
 
 
-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
@@ -2616,7 +2760,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
                !!wpa_auth->conf.wpa_strict_rekey,
                dot11RSNAConfigGroupUpdateCount,
                dot11RSNAConfigPairwiseUpdateCount,
-               wpa_cipher_bits(wpa_auth->conf.wpa_group),
+               wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
                dot11RSNAConfigPMKLifetime,
                dot11RSNAConfigPMKReauthThreshold,
                dot11RSNAConfigSATimeout,
@@ -2659,29 +2803,10 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
 
        /* 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
+       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(
@@ -2819,6 +2944,22 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 }
 
 
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+                          const u8 *sta_addr)
+{
+       struct rsn_pmksa_cache_entry *pmksa;
+
+       if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+               return;
+       pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+       if (pmksa) {
+               wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+                          MACSTR " based on request", MAC2STR(sta_addr));
+               pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+       }
+}
+
+
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
@@ -2899,3 +3040,11 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
                                       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);
+}
index ce2751e..ebfe86f 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_AUTH_H
@@ -164,6 +158,11 @@ struct wpa_auth_config {
        int pmk_r1_push;
        int ft_over_ds;
 #endif /* CONFIG_IEEE80211R */
+       int disable_gtk;
+       int ap_mlme;
+#ifdef CONFIG_TESTING_OPTIONS
+       double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 typedef enum {
@@ -181,7 +180,7 @@ struct wpa_auth_callbacks {
        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);
+       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);
@@ -202,6 +201,8 @@ struct wpa_auth_callbacks {
        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 */
 };
 
@@ -262,6 +263,8 @@ 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);
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+                          const u8 *sta_addr);
 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);
@@ -284,4 +287,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
 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 */
index 2d1bbe4..1bb5d97 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - IEEE 802.11r - Fast BSS Transition
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -58,6 +52,19 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *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;
@@ -409,7 +416,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
                pad_len = 8 - pad_len;
        if (key_len + pad_len < 16)
                pad_len += 8;
-       if (pad_len) {
+       if (pad_len && key_len < sizeof(keybuf)) {
                os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
                os_memset(keybuf + key_len, 0, pad_len);
                keybuf[key_len] = 0xdd;
@@ -477,7 +484,8 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
 #endif /* CONFIG_IEEE80211W */
 
 
-static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
+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;
@@ -510,7 +518,7 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
        }
 
 #ifdef NEED_AP_MLME
-       if (parse.wmm_tspec) {
+       if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
                struct wmm_tspec_element *tspec;
                int res;
 
@@ -547,13 +555,35 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
        }
 #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(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
+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;
@@ -575,7 +605,7 @@ static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
                                break;
                        rpos += 2 + rpos[1];
                }
-               pos = wpa_ft_process_rdie(pos, end, rdie->id,
+               pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
                                          rdie->descr_count,
                                          start, rpos - start);
        }
@@ -684,7 +714,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 
        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);
+               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,
@@ -723,13 +754,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
        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 {
+       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;
@@ -851,7 +878,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
        wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
                    sm->ANonce, WPA_NONCE_LEN);
 
-       ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48;
+       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);
@@ -1067,8 +1094,16 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
 
        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;
        }
 
@@ -1131,6 +1166,8 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
 
        /* RRB - Forward action frame to the target AP */
        frame = os_malloc(sizeof(*frame) + len);
+       if (frame == NULL)
+               return -1;
        frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
        frame->packet_type = FT_PACKET_REQUEST;
        frame->action_length = host_to_le16(len);
@@ -1181,6 +1218,10 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
        rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
 
        frame = os_malloc(sizeof(*frame) + rlen);
+       if (frame == NULL) {
+               os_free(resp_ies);
+               return -1;
+       }
        frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
        frame->packet_type = FT_PACKET_RESPONSE;
        frame->action_length = host_to_le16(rlen);
index 56bab23..e2be1ea 100644 (file)
@@ -1,21 +1,16 @@
 /*
  * hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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/sae.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eap_server/eap.h"
@@ -33,6 +28,7 @@
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+                                 struct hostapd_config *iconf,
                                  struct wpa_auth_config *wconf)
 {
        os_memset(wconf, 0, sizeof(*wconf));
@@ -76,6 +72,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        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 */
+#ifdef CONFIG_TESTING_OPTIONS
+       wconf->corrupt_gtk_rekey_mic_probability =
+               iconf->corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 }
 
 
@@ -115,10 +118,10 @@ static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
 }
 
 
-static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
 {
        struct hostapd_data *hapd = ctx;
-       michael_mic_failure(hapd, addr, 0);
+       return michael_mic_failure(hapd, addr, 0);
 }
 
 
@@ -187,9 +190,33 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
 {
        struct hostapd_data *hapd = ctx;
        struct sta_info *sta = ap_get_sta(hapd, addr);
-       if (sta && sta->psk)
-               return sta->psk;
-       return hostapd_get_psk(hapd->conf, addr, prev_psk);
+       const u8 *psk;
+
+#ifdef CONFIG_SAE
+       if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+               if (!sta->sae || prev_psk)
+                       return NULL;
+               return sta->sae->pmk;
+       }
+#endif /* CONFIG_SAE */
+
+       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;
 }
 
 
@@ -300,12 +327,13 @@ static int hostapd_wpa_auth_for_each_auth(
 {
        struct hostapd_data *hapd = ctx;
        struct wpa_auth_iface_iter_data data;
-       if (hapd->iface->for_each_interface == NULL)
+       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->for_each_interface(hapd->iface->interfaces,
-                                              wpa_auth_iface_iter, &data);
+       return hapd->iface->interfaces->for_each_interface(
+               hapd->iface->interfaces, wpa_auth_iface_iter, &data);
 }
 
 
@@ -357,16 +385,17 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
        int ret;
 
 #ifdef CONFIG_IEEE80211R
-       if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
+       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->for_each_interface(hapd->iface->interfaces,
-                                                     hostapd_wpa_auth_ft_iter,
-                                                     &idata);
+               res = hapd->iface->interfaces->for_each_interface(
+                       hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
+                       &idata);
                if (res == 1)
                        return data_len;
        }
@@ -431,6 +460,9 @@ 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;
@@ -464,6 +496,14 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                      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 */
 
 
@@ -474,9 +514,11 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
        const u8 *wpa_ie;
        size_t wpa_ie_len;
 
-       hostapd_wpa_auth_conf(hapd->conf, &_conf);
+       hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_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;
@@ -495,6 +537,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 #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) {
@@ -545,7 +588,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 void hostapd_reconfig_wpa(struct hostapd_data *hapd)
 {
        struct wpa_auth_config wpa_auth_conf;
-       hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
+       hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf);
        wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
 }
 
index 79d7e05..1b13ae7 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / WPA authenticator glue code
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_AUTH_GLUE_H
index d82192a..97489d3 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_AUTH_I_H
@@ -69,10 +63,11 @@ struct wpa_state_machine {
        Boolean pairwise_set;
        int keycount;
        Boolean Pair;
-       struct {
+       struct wpa_key_replay_counter {
                u8 counter[WPA_REPLAY_COUNTER_LEN];
                Boolean valid;
-       } key_replay[RSNA_MAX_EAPOL_RETRIES];
+       } 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;
@@ -87,10 +82,12 @@ struct wpa_state_machine {
        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;
index 4db04bb..cdfcca1 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - WPA/RSN IE and KDE definitions
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -35,6 +29,7 @@ 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;
@@ -42,46 +37,25 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
        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 {
+       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;
 
-       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++;
-       }
-
+       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;
@@ -118,28 +92,23 @@ 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;
+       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);
 
-       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 {
+       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;
@@ -154,21 +123,9 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        }
 #endif /* CONFIG_RSN_TESTING */
 
-       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++;
-       }
+       res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+       num_suites += res;
+       pos += res * RSN_SELECTOR_LEN;
 
 #ifdef CONFIG_RSN_TESTING
        if (rsn_testing) {
@@ -231,6 +188,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t 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) {
@@ -450,36 +419,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                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 = RSN_CIPHER_SUITE_CCMP;
-               if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+               selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+                                              data.pairwise_cipher);
+               if (!selector)
                        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 = wpa_cipher_to_suite(WPA_PROTO_RSN,
+                                              data.group_cipher);
+               if (!selector)
                        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);
@@ -491,30 +452,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                        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;
+               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_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_to_suite(WPA_PROTO_WPA,
+                                              data.group_cipher);
+               if (!selector)
                        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) {
@@ -550,6 +497,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        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
@@ -611,10 +564,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        }
 #endif /* CONFIG_IEEE80211R */
 
-       if (ciphers & WPA_CIPHER_CCMP)
-               sm->pairwise = WPA_CIPHER_CCMP;
-       else
-               sm->pairwise = WPA_CIPHER_TKIP;
+       sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+       if (sm->pairwise < 0)
+               return WPA_INVALID_PAIRWISE;
 
        /* TODO: clear WPA/WPA2 state if STA changes from one to another */
        if (wpa_ie[0] == WLAN_EID_RSN)
index 61d4cb4..4999139 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd - WPA/RSN IE and KDE definitions
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_AUTH_IE_H
index 817012e..69b34fe 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -17,7 +11,6 @@
 #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"
@@ -26,6 +19,7 @@
 #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"
@@ -43,13 +37,15 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 
 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);
+                                   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;
+       struct hostapd_data *calling_hapd;
 };
 
 
@@ -62,7 +58,14 @@ static int wps_for_each(struct hostapd_iface *iface, void *ctx)
                return 0;
        for (j = 0; j < iface->num_bss; j++) {
                struct hostapd_data *hapd = iface->bss[j];
-               int ret = data->func(hapd, data->ctx);
+               int ret;
+
+               if (hapd != data->calling_hapd &&
+                   (hapd->conf->wps_independent ||
+                    data->calling_hapd->conf->wps_independent))
+                       continue;
+
+               ret = data->func(hapd, data->ctx);
                if (ret)
                        return ret;
        }
@@ -79,10 +82,12 @@ static int hostapd_wps_for_each(struct hostapd_data *hapd,
        struct wps_for_each_data data;
        data.func = func;
        data.ctx = ctx;
-       if (iface->for_each_interface == NULL)
+       data.calling_hapd = hapd;
+       if (iface->interfaces == NULL ||
+           iface->interfaces->for_each_interface == NULL)
                return wps_for_each(iface, &data);
-       return iface->for_each_interface(iface->interfaces, wps_for_each,
-                                        &data);
+       return iface->interfaces->for_each_interface(iface->interfaces,
+                                                    wps_for_each, &data);
 }
 
 
@@ -189,19 +194,23 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
 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);
+               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 *uuid_e, const u8 *dev_pw,
+                                      size_t dev_pw_len)
 {
        struct hostapd_data *hapd = ctx;
        char uuid[40];
@@ -215,6 +224,8 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
                                         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);
 }
 
@@ -253,7 +264,8 @@ 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) {
+       if (iface->interfaces == NULL ||
+           iface->interfaces->reload_config(iface) < 0) {
                wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
                           "configuration");
        }
@@ -274,6 +286,114 @@ static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
 }
 
 
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+                                      const struct wps_credential *cred)
+{
+       struct hostapd_bss_config *bss = hapd->conf;
+
+       wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+       bss->wps_state = 2;
+       if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+               os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+               bss->ssid.ssid_len = cred->ssid_len;
+               bss->ssid.ssid_set = 1;
+       }
+
+       if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+           (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+               bss->wpa = 3;
+       else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+               bss->wpa = 2;
+       else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+               bss->wpa = 1;
+       else
+               bss->wpa = 0;
+
+       if (bss->wpa) {
+               if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+                       bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+               if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+                       bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+               bss->wpa_pairwise = 0;
+               if (cred->encr_type & WPS_ENCR_AES)
+                       bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+               if (cred->encr_type & WPS_ENCR_TKIP)
+                       bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+               bss->rsn_pairwise = bss->wpa_pairwise;
+               bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+                                                           bss->wpa_pairwise,
+                                                           bss->rsn_pairwise);
+
+               if (cred->key_len >= 8 && cred->key_len < 64) {
+                       os_free(bss->ssid.wpa_passphrase);
+                       bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+                       if (bss->ssid.wpa_passphrase)
+                               os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+                                         cred->key_len);
+                       os_free(bss->ssid.wpa_psk);
+                       bss->ssid.wpa_psk = NULL;
+               } else if (cred->key_len == 64) {
+                       os_free(bss->ssid.wpa_psk);
+                       bss->ssid.wpa_psk =
+                               os_zalloc(sizeof(struct hostapd_wpa_psk));
+                       if (bss->ssid.wpa_psk &&
+                           hexstr2bin((const char *) cred->key,
+                                      bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+                               bss->ssid.wpa_psk->group = 1;
+                               os_free(bss->ssid.wpa_passphrase);
+                               bss->ssid.wpa_passphrase = NULL;
+                       }
+               }
+               bss->auth_algs = 1;
+       } else {
+               if ((cred->auth_type & WPS_AUTH_OPEN) &&
+                   (cred->auth_type & WPS_AUTH_SHARED))
+                       bss->auth_algs = 3;
+               else if (cred->auth_type & WPS_AUTH_SHARED)
+                       bss->auth_algs = 2;
+               else
+                       bss->auth_algs = 1;
+               if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
+                   cred->key_idx <= 4) {
+                       struct hostapd_wep_keys *wep = &bss->ssid.wep;
+                       int idx = cred->key_idx;
+                       if (idx)
+                               idx--;
+                       wep->idx = idx;
+                       if (cred->key_len == 10 || cred->key_len == 26) {
+                               os_free(wep->key[idx]);
+                               wep->key[idx] = os_malloc(cred->key_len / 2);
+                               if (wep->key[idx] == NULL ||
+                                   hexstr2bin((const char *) cred->key,
+                                              wep->key[idx],
+                                              cred->key_len / 2))
+                                       return -1;
+                               wep->len[idx] = cred->key_len / 2;
+                       } else {
+                               os_free(wep->key[idx]);
+                               wep->key[idx] = os_malloc(cred->key_len);
+                               if (wep->key[idx] == NULL)
+                                       return -1;
+                               os_memcpy(wep->key[idx], cred->key,
+                                         cred->key_len);
+                               wep->len[idx] = cred->key_len;
+                       }
+                       wep->keys_set = 1;
+               }
+       }
+
+       /* 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);
+
+       return 0;
+}
+
+
 static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
        const struct wps_credential *cred = ctx;
@@ -340,6 +460,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
        }
        hapd->wps->wps_state = WPS_STATE_CONFIGURED;
 
+       if (hapd->iface->config_fname == NULL)
+               return hapd_wps_reconfig_in_memory(hapd, cred);
        len = os_strlen(hapd->iface->config_fname) + 5;
        tmp_fname = os_malloc(len);
        if (tmp_fname == NULL)
@@ -367,10 +489,17 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 
        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 (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)))
@@ -460,6 +589,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
                        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") ||
@@ -512,6 +642,8 @@ static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
 
        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);
@@ -533,8 +665,10 @@ static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
         * force attacks.
         */
        hapd->ap_pin_failures++;
-       wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
-                  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;
 
@@ -543,7 +677,15 @@ static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
 
        wps_registrar_update_ie(hapd->wps->registrar);
 
-       if (!hapd->conf->ap_setup_locked) {
+       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 &&
@@ -569,6 +711,29 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
 }
 
 
+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 */
@@ -628,6 +793,9 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
                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);
@@ -655,7 +823,8 @@ static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
                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)) {
+               if (hapd->wps && !hapd->conf->wps_independent &&
+                   !is_nil_uuid(hapd->wps->uuid)) {
                        *uuid = hapd->wps->uuid;
                        return 1;
                }
@@ -668,10 +837,12 @@ static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
 static const u8 * get_own_uuid(struct hostapd_iface *iface)
 {
        const u8 *uuid;
-       if (iface->for_each_interface == NULL)
+       if (iface->interfaces == NULL ||
+           iface->interfaces->for_each_interface == NULL)
                return NULL;
        uuid = NULL;
-       iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid);
+       iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
+                                             &uuid);
        return uuid;
 }
 
@@ -687,10 +858,11 @@ static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
 static int interface_count(struct hostapd_iface *iface)
 {
        int count = 0;
-       if (iface->for_each_interface == NULL)
+       if (iface->interfaces == NULL ||
+           iface->interfaces->for_each_interface == NULL)
                return 0;
-       iface->for_each_interface(iface->interfaces, count_interface_cb,
-                                 &count);
+       iface->interfaces->for_each_interface(iface->interfaces,
+                                             count_interface_cb, &count);
        return count;
 }
 
@@ -745,7 +917,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        if (is_nil_uuid(hapd->conf->uuid)) {
                const u8 *uuid;
                uuid = get_own_uuid(hapd->iface);
-               if (uuid) {
+               if (uuid && !conf->wps_independent) {
                        os_memcpy(wps->uuid, uuid, UUID_LEN);
                        wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
                                    "interface", wps->uuid, UUID_LEN);
@@ -903,6 +1075,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        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");
 
@@ -952,6 +1127,20 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
 }
 
 
+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);
@@ -966,9 +1155,8 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        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);
+       hostapd_wps_nfc_clear(hapd->wps);
        os_free(hapd->wps);
        hapd->wps = NULL;
        hostapd_wps_clear_ies(hapd);
@@ -1066,63 +1254,28 @@ int hostapd_wps_button_pushed(struct hostapd_data *hapd,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
-                         char *path, char *method, char *name)
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
 {
-       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 (hapd->wps == NULL)
+               return 0;
 
-       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, NULL, "any",
-                               wpabuf_head(wps->oob_conf.dev_password), 0) <
-           0)
-               goto error;
+       wps_registrar_wps_cancel(hapd->wps->registrar);
+       ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
 
        return 0;
+}
 
-error:
-       wpabuf_free(wps->dh_pubkey);
-       wps->dh_pubkey = NULL;
-       wpabuf_free(wps->dh_privkey);
-       wps->dh_privkey = NULL;
-       return -1;
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+       return hostapd_wps_for_each(hapd, wps_cancel, NULL);
 }
-#endif /* CONFIG_WPS_OOB */
 
 
 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)
+                                   const u8 *ie, size_t ie_len,
+                                   int ssi_signal)
 {
        struct hostapd_data *hapd = ctx;
        struct wpabuf *wps_ie;
@@ -1293,6 +1446,7 @@ 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);
@@ -1438,3 +1592,183 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
 
        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_hs_cr(struct hostapd_data *hapd, int ndef)
+{
+       /*
+        * Handover Select carrier record for WPS uses the same format as
+        * configuration token.
+        */
+       return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+       if (hapd->conf->wps_nfc_pw_from_config) {
+               return wps_nfc_token_build(ndef,
+                                          hapd->conf->wps_nfc_dev_pw_id,
+                                          hapd->conf->wps_nfc_dh_pubkey,
+                                          hapd->conf->wps_nfc_dev_pw);
+       }
+
+       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;
+       struct wpabuf *pw;
+
+       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);
+       pw = hapd->conf->wps_nfc_dev_pw;
+       wps->ap_nfc_dev_pw = wpabuf_alloc(
+               wpabuf_len(pw) * 2 + 1);
+       if (wps->ap_nfc_dev_pw) {
+               wpa_snprintf_hex_uppercase(
+                       (char *) wpabuf_put(wps->ap_nfc_dev_pw,
+                                           wpabuf_len(pw) * 2),
+                       wpabuf_len(pw) * 2 + 1,
+                       wpabuf_head(pw), wpabuf_len(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 */
index 6b28c13..a2c2cf0 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPS_HOSTAPD_H
@@ -26,8 +20,7 @@ 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_start_oob(struct hostapd_data *hapd, char *device_type,
-                         char *path, char *method, char *name);
+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);
@@ -38,6 +31,14 @@ int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
 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_hs_cr(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 */
 
@@ -73,6 +74,11 @@ static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
        return 0;
 }
 
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+       return 0;
+}
+
 #endif /* CONFIG_WPS */
 
 #endif /* WPS_HOSTAPD_H */
index 6082053..281dd8a 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Common definitions
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DEFS_H
@@ -32,6 +26,8 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #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)
@@ -43,11 +39,17 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #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));
 }
 
@@ -55,13 +57,21 @@ 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_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_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)
@@ -81,14 +91,21 @@ 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 {
@@ -97,7 +114,10 @@ enum wpa_alg {
        WPA_ALG_TKIP,
        WPA_ALG_CCMP,
        WPA_ALG_IGTK,
-       WPA_ALG_PMK
+       WPA_ALG_PMK,
+       WPA_ALG_GCMP,
+       WPA_ALG_SMS4,
+       WPA_ALG_KRK
 };
 
 /**
@@ -108,7 +128,9 @@ enum wpa_cipher {
        CIPHER_WEP40,
        CIPHER_TKIP,
        CIPHER_CCMP,
-       CIPHER_WEP104
+       CIPHER_WEP104,
+       CIPHER_GCMP,
+       CIPHER_SMS4
 };
 
 /**
@@ -124,7 +146,12 @@ enum wpa_key_mgmt {
        KEY_MGMT_FT_PSK,
        KEY_MGMT_802_1X_SHA256,
        KEY_MGMT_PSK_SHA256,
-       KEY_MGMT_WPS
+       KEY_MGMT_WPS,
+       KEY_MGMT_SAE,
+       KEY_MGMT_FT_SAE,
+       KEY_MGMT_WAPI_PSK,
+       KEY_MGMT_WAPI_CERT,
+       KEY_MGMT_CCKM
 };
 
 /**
@@ -259,8 +286,9 @@ enum wpa_states {
 enum mfp_options {
        NO_MGMT_FRAME_PROTECTION = 0,
        MGMT_FRAME_PROTECTION_OPTIONAL = 1,
-       MGMT_FRAME_PROTECTION_REQUIRED = 2
+       MGMT_FRAME_PROTECTION_REQUIRED = 2,
 };
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
 
 /**
  * enum hostapd_hw_mode - Hardware mode
@@ -269,6 +297,7 @@ enum hostapd_hw_mode {
        HOSTAPD_MODE_IEEE80211B,
        HOSTAPD_MODE_IEEE80211G,
        HOSTAPD_MODE_IEEE80211A,
+       HOSTAPD_MODE_IEEE80211AD,
        NUM_HOSTAPD_MODES
 };
 
index d70e62d..4811f38 100644 (file)
@@ -2,14 +2,8 @@
  * EAPOL definitions shared between hostapd and wpa_supplicant
  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAPOL_COMMON_H
@@ -44,4 +38,44 @@ enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
 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 */
index babdaa3..cff9254 100644 (file)
@@ -1,16 +1,10 @@
 /*
  * Generic advertisement service (GAS) (IEEE 802.11u)
  * Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -37,7 +31,7 @@ gas_build_req(u8 action, u8 dialog_token, size_t size)
 }
 
 
-static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
 {
        return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
                             size);
index 2f8d2cb..306adc5 100644 (file)
@@ -1,21 +1,16 @@
 /*
  * Generic advertisement service (GAS) (IEEE 802.11u)
  * Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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);
index 43cb2c6..aab8ac6 100644 (file)
@@ -1,20 +1,15 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 
 #include "common.h"
+#include "defs.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
 
@@ -103,6 +98,16 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        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 "
@@ -254,6 +259,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
                        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;
@@ -263,6 +276,19 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
                        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)
@@ -389,3 +415,133 @@ const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
                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;
+}
+
+
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
+{
+       enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
+
+       if (freq >= 2412 && freq <= 2472) {
+               mode = HOSTAPD_MODE_IEEE80211G;
+               *channel = (freq - 2407) / 5;
+       } else if (freq == 2484) {
+               mode = HOSTAPD_MODE_IEEE80211B;
+               *channel = 14;
+       } else if (freq >= 4900 && freq < 5000) {
+               mode = HOSTAPD_MODE_IEEE80211A;
+               *channel = (freq - 4000) / 5;
+       } else if (freq >= 5000 && freq < 5900) {
+               mode = HOSTAPD_MODE_IEEE80211A;
+               *channel = (freq - 5000) / 5;
+       } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+               mode = HOSTAPD_MODE_IEEE80211AD;
+               *channel = (freq - 56160) / 2160;
+       }
+
+       return mode;
+}
+
+
+static int is_11b(u8 rate)
+{
+       return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+       int num_11b = 0, num_others = 0;
+       int i;
+
+       if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+               return 0;
+
+       for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+               if (is_11b(elems->supp_rates[i]))
+                       num_11b++;
+               else
+                       num_others++;
+       }
+
+       for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+            i++) {
+               if (is_11b(elems->ext_supp_rates[i]))
+                       num_11b++;
+               else
+                       num_others++;
+       }
+
+       return num_11b > 0 && num_others == 0;
+}
index 60f0974..68c6b96 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_11_COMMON_H
@@ -39,10 +33,17 @@ struct ieee802_11_elems {
        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;
@@ -66,9 +67,15 @@ struct ieee802_11_elems {
        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;
@@ -82,4 +89,18 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 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);
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems);
+
 #endif /* IEEE802_11_COMMON_H */
index 66801fd..137c309 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2002-2009, Jouni Malinen <j@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_11_DEFS_H
@@ -82,6 +76,7 @@
 #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_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) */
 /* EIDs defined by IEEE 802.11h - END */
 #define WLAN_EID_ERP_INFO 42
 #define WLAN_EID_HT_CAP 45
+#define WLAN_EID_QOS 46
 #define WLAN_EID_RSN 48
 #define WLAN_EID_EXT_SUPP_RATES 50
 #define WLAN_EID_MOBILITY_DOMAIN 54
 #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
 
 
 #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
@@ -493,6 +508,17 @@ struct ieee80211_mgmt {
                                } 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 {
@@ -513,12 +539,33 @@ struct ieee80211_mgmt {
                                         * 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;
+                               struct {
+                                       u8 action; /* 6 */
+                                       u8 dialog_token;
+                                       u8 query_reason;
+                                       /* BSS Transition Candidate List
+                                        * Entries (optional) */
+                                       u8 variable[0];
+                               } STRUCT_PACKED bss_tm_query;
                        } 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;
@@ -537,6 +584,24 @@ struct ieee80211_ht_operation {
        u8 basic_set[16];
 } STRUCT_PACKED;
 
+
+struct ieee80211_vht_capabilities {
+       le32 vht_capabilities_info;
+       struct {
+               le16 rx_map;
+               le16 rx_highest;
+               le16 tx_map;
+               le16 tx_highest;
+       } vht_supported_mcs_set;
+} 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 */
@@ -631,14 +696,51 @@ struct ieee80211_ht_operation {
 #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))
+
+/* VHT channel widths */
+#define VHT_CHANWIDTH_USE_HT   0
+#define VHT_CHANWIDTH_80MHZ    1
+#define VHT_CHANWIDTH_160MHZ   2
+#define VHT_CHANWIDTH_80P80MHZ 3
+
 #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
@@ -752,6 +854,16 @@ enum {
 };
 
 
+#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
@@ -850,6 +962,7 @@ enum p2p_service_protocol_type {
        P2P_SERV_BONJOUR = 1,
        P2P_SERV_UPNP = 2,
        P2P_SERV_WS_DISCOVERY = 3,
+       P2P_SERV_WIFI_DISPLAY = 4,
        P2P_SERV_VENDOR_SPECIFIC = 255
 };
 
@@ -861,6 +974,20 @@ enum p2p_sd_status {
 };
 
 
+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 */
@@ -873,10 +1000,22 @@ enum p2p_sd_status {
 #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_FT_8021X                0x000FAC03
+#define WLAN_AKM_SUITE_FT_PSK          0x000FAC04
+#define WLAN_AKM_SUITE_CCKM            0x00409600
 
 
 /* IEEE 802.11v - WNM Action field values */
@@ -918,4 +1057,73 @@ enum wnm_action {
 #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 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+       WNM_BSS_TM_ACCEPT = 0,
+       WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+       WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+       WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+       WNM_BSS_TM_REJECT_UNDESIRED = 4,
+       WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+       WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+       WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+       WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
+
+#define WNM_NEIGHBOR_TSF                         1
+#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING    2
+#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE    3
+#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION    4
+#define WNM_NEIGHBOR_BEARING                     5
+#define WNM_NEIGHBOR_MEASUREMENT_PILOT          66
+#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
+#define WNM_NEIGHBOR_MULTIPLE_BSSID             71
+
+/* 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 */
index cc900be..858b51d 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - privilege separation commands
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PRIVSEP_COMMANDS_H
diff --git a/src/common/sae.c b/src/common/sae.c
new file mode 100644 (file)
index 0000000..bce60a3
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/dh_groups.h"
+#include "ieee802_11_defs.h"
+#include "sae.h"
+
+
+int sae_set_group(struct sae_data *sae, int group)
+{
+       struct sae_temporary_data *tmp;
+
+       sae_clear_data(sae);
+       tmp = sae->tmp = os_zalloc(sizeof(*tmp));
+       if (tmp == NULL)
+               return -1;
+
+       /* First, check if this is an ECC group */
+       tmp->ec = crypto_ec_init(group);
+       if (tmp->ec) {
+               sae->group = group;
+               tmp->prime_len = crypto_ec_prime_len(tmp->ec);
+               tmp->prime = crypto_ec_get_prime(tmp->ec);
+               tmp->order = crypto_ec_get_order(tmp->ec);
+               return 0;
+       }
+
+       /* Not an ECC group, check FFC */
+       tmp->dh = dh_groups_get(group);
+       if (tmp->dh) {
+               sae->group = group;
+               tmp->prime_len = tmp->dh->prime_len;
+               if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
+                       sae_clear_data(sae);
+                       return -1;
+               }
+
+               tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
+                                                       tmp->prime_len);
+               if (tmp->prime_buf == NULL) {
+                       sae_clear_data(sae);
+                       return -1;
+               }
+               tmp->prime = tmp->prime_buf;
+
+               tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
+                                                       tmp->dh->order_len);
+               if (tmp->order_buf == NULL) {
+                       sae_clear_data(sae);
+                       return -1;
+               }
+               tmp->order = tmp->order_buf;
+
+               return 0;
+       }
+
+       /* Unsupported group */
+       return -1;
+}
+
+
+void sae_clear_temp_data(struct sae_data *sae)
+{
+       struct sae_temporary_data *tmp;
+       if (sae == NULL || sae->tmp == NULL)
+               return;
+       tmp = sae->tmp;
+       crypto_ec_deinit(tmp->ec);
+       crypto_bignum_deinit(tmp->prime_buf, 0);
+       crypto_bignum_deinit(tmp->order_buf, 0);
+       crypto_bignum_deinit(tmp->sae_rand, 1);
+       crypto_bignum_deinit(tmp->pwe_ffc, 1);
+       crypto_bignum_deinit(tmp->own_commit_scalar, 0);
+       crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
+       crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
+       crypto_ec_point_deinit(tmp->pwe_ecc, 1);
+       crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
+       crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
+       os_free(sae->tmp);
+       sae->tmp = NULL;
+}
+
+
+void sae_clear_data(struct sae_data *sae)
+{
+       if (sae == NULL)
+               return;
+       sae_clear_temp_data(sae);
+       crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+       os_memset(sae, 0, sizeof(*sae));
+}
+
+
+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
+{
+       size_t i;
+       for (i = len - 1; i > 0; i--)
+               buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
+       buf[0] >>= bits;
+}
+
+
+static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
+{
+       u8 val[SAE_MAX_PRIME_LEN];
+       int iter = 0;
+       struct crypto_bignum *bn = NULL;
+       int order_len_bits = crypto_bignum_bits(sae->tmp->order);
+       size_t order_len = (order_len_bits + 7) / 8;
+
+       if (order_len > sizeof(val))
+               return NULL;
+
+       for (;;) {
+               if (iter++ > 100)
+                       return NULL;
+               if (random_get_bytes(val, order_len) < 0)
+                       return NULL;
+               if (order_len_bits % 8)
+                       buf_shift_right(val, order_len, 8 - order_len_bits % 8);
+               bn = crypto_bignum_init_set(val, order_len);
+               if (bn == NULL)
+                       return NULL;
+               if (crypto_bignum_is_zero(bn) ||
+                   crypto_bignum_is_one(bn) ||
+                   crypto_bignum_cmp(bn, sae->tmp->order) >= 0)
+                       continue;
+               break;
+       }
+
+       os_memset(val, 0, order_len);
+       return bn;
+}
+
+
+static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
+{
+       crypto_bignum_deinit(sae->tmp->sae_rand, 1);
+       sae->tmp->sae_rand = sae_get_rand(sae);
+       if (sae->tmp->sae_rand == NULL)
+               return NULL;
+       return sae_get_rand(sae);
+}
+
+
+static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
+{
+       wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
+                  " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
+       if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+               os_memcpy(key, addr1, ETH_ALEN);
+               os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
+       } else {
+               os_memcpy(key, addr2, ETH_ALEN);
+               os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
+       }
+}
+
+
+static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+                                struct crypto_ec_point *pwe)
+{
+       u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
+       struct crypto_bignum *x;
+       int y_bit;
+       size_t bits;
+
+       if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+                                sae->tmp->prime_len) < 0)
+               return -1;
+
+       wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+       /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+       bits = crypto_ec_prime_len_bits(sae->tmp->ec);
+       sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+                       prime, sae->tmp->prime_len, pwd_value, bits);
+       if (bits % 8)
+               buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+       wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+                       pwd_value, sae->tmp->prime_len);
+
+       if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+               return 0;
+
+       y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
+
+       x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+       if (x == NULL)
+               return -1;
+       if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
+               crypto_bignum_deinit(x, 0);
+               wpa_printf(MSG_DEBUG, "SAE: No solution found");
+               return 0;
+       }
+       crypto_bignum_deinit(x, 0);
+
+       wpa_printf(MSG_DEBUG, "SAE: PWE found");
+
+       return 1;
+}
+
+
+static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
+                                struct crypto_bignum *pwe)
+{
+       u8 pwd_value[SAE_MAX_PRIME_LEN];
+       size_t bits = sae->tmp->prime_len * 8;
+       u8 exp[1];
+       struct crypto_bignum *a, *b;
+       int res;
+
+       wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+       /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+       sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+                       sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+                       bits);
+       if (bits % 8)
+               buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+       wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
+                       sae->tmp->prime_len);
+
+       if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
+       {
+               wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
+               return 0;
+       }
+
+       /* PWE = pwd-value^((p-1)/r) modulo p */
+
+       a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+
+       if (sae->tmp->dh->safe_prime) {
+               /*
+                * r = (p-1)/2 for the group used here, so this becomes:
+                * PWE = pwd-value^2 modulo p
+                */
+               exp[0] = 2;
+               b = crypto_bignum_init_set(exp, sizeof(exp));
+       } else {
+               /* Calculate exponent: (p-1)/r */
+               exp[0] = 1;
+               b = crypto_bignum_init_set(exp, sizeof(exp));
+               if (b == NULL ||
+                   crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
+                   crypto_bignum_div(b, sae->tmp->order, b) < 0) {
+                       crypto_bignum_deinit(b, 0);
+                       b = NULL;
+               }
+       }
+
+       if (a == NULL || b == NULL)
+               res = -1;
+       else
+               res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+
+       crypto_bignum_deinit(a, 0);
+       crypto_bignum_deinit(b, 0);
+
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
+               return -1;
+       }
+
+       /* if (PWE > 1) --> found */
+       if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
+               wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "SAE: PWE found");
+       return 1;
+}
+
+
+static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+                             const u8 *addr2, const u8 *password,
+                             size_t password_len)
+{
+       u8 counter, k = 4;
+       u8 addrs[2 * ETH_ALEN];
+       const u8 *addr[2];
+       size_t len[2];
+       int found = 0;
+       struct crypto_ec_point *pwe_tmp;
+
+       if (sae->tmp->pwe_ecc == NULL) {
+               sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
+               if (sae->tmp->pwe_ecc == NULL)
+                       return -1;
+       }
+       pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
+       if (pwe_tmp == NULL)
+               return -1;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+                             password, password_len);
+
+       /*
+        * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+        * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+        *              password || counter)
+        */
+       sae_pwd_seed_key(addr1, addr2, addrs);
+
+       addr[0] = password;
+       len[0] = password_len;
+       addr[1] = &counter;
+       len[1] = sizeof(counter);
+
+       /*
+        * Continue for at least k iterations to protect against side-channel
+        * attacks that attempt to determine the number of iterations required
+        * in the loop.
+        */
+       for (counter = 1; counter < k || !found; counter++) {
+               u8 pwd_seed[SHA256_MAC_LEN];
+               int res;
+
+               if (counter > 200) {
+                       /* This should not happen in practice */
+                       wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+                       break;
+               }
+
+               wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+               if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+                                      pwd_seed) < 0)
+                       break;
+               res = sae_test_pwd_seed_ecc(sae, pwd_seed,
+                                           found ? pwe_tmp :
+                                           sae->tmp->pwe_ecc);
+               if (res < 0)
+                       break;
+               if (res == 0)
+                       continue;
+               if (found) {
+                       wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
+                                  "already selected)");
+               } else {
+                       wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+                       found = 1;
+               }
+       }
+
+       crypto_ec_point_deinit(pwe_tmp, 1);
+
+       return found ? 0 : -1;
+}
+
+
+static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+                             const u8 *addr2, const u8 *password,
+                             size_t password_len)
+{
+       u8 counter;
+       u8 addrs[2 * ETH_ALEN];
+       const u8 *addr[2];
+       size_t len[2];
+       int found = 0;
+
+       if (sae->tmp->pwe_ffc == NULL) {
+               sae->tmp->pwe_ffc = crypto_bignum_init();
+               if (sae->tmp->pwe_ffc == NULL)
+                       return -1;
+       }
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+                             password, password_len);
+
+       /*
+        * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+        * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+        *              password || counter)
+        */
+       sae_pwd_seed_key(addr1, addr2, addrs);
+
+       addr[0] = password;
+       len[0] = password_len;
+       addr[1] = &counter;
+       len[1] = sizeof(counter);
+
+       for (counter = 1; !found; counter++) {
+               u8 pwd_seed[SHA256_MAC_LEN];
+               int res;
+
+               if (counter > 200) {
+                       /* This should not happen in practice */
+                       wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+                       break;
+               }
+
+               wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+               if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+                                      pwd_seed) < 0)
+                       break;
+               res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
+               if (res < 0)
+                       break;
+               if (res > 0) {
+                       wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+                       found = 1;
+               }
+       }
+
+       return found ? 0 : -1;
+}
+
+
+static int sae_derive_commit_element_ecc(struct sae_data *sae,
+                                        struct crypto_bignum *mask)
+{
+       /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+       if (!sae->tmp->own_commit_element_ecc) {
+               sae->tmp->own_commit_element_ecc =
+                       crypto_ec_point_init(sae->tmp->ec);
+               if (!sae->tmp->own_commit_element_ecc)
+                       return -1;
+       }
+
+       if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
+                               sae->tmp->own_commit_element_ecc) < 0 ||
+           crypto_ec_point_invert(sae->tmp->ec,
+                                  sae->tmp->own_commit_element_ecc) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int sae_derive_commit_element_ffc(struct sae_data *sae,
+                                        struct crypto_bignum *mask)
+{
+       /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+       if (!sae->tmp->own_commit_element_ffc) {
+               sae->tmp->own_commit_element_ffc = crypto_bignum_init();
+               if (!sae->tmp->own_commit_element_ffc)
+                       return -1;
+       }
+
+       if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
+                                 sae->tmp->own_commit_element_ffc) < 0 ||
+           crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
+                                 sae->tmp->prime,
+                                 sae->tmp->own_commit_element_ffc) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int sae_derive_commit(struct sae_data *sae)
+{
+       struct crypto_bignum *mask;
+       int ret = -1;
+
+       mask = sae_get_rand_and_mask(sae);
+       if (mask == NULL) {
+               wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
+               return -1;
+       }
+
+       /* commit-scalar = (rand + mask) modulo r */
+       if (!sae->tmp->own_commit_scalar) {
+               sae->tmp->own_commit_scalar = crypto_bignum_init();
+               if (!sae->tmp->own_commit_scalar)
+                       goto fail;
+       }
+       crypto_bignum_add(sae->tmp->sae_rand, mask,
+                         sae->tmp->own_commit_scalar);
+       crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
+                         sae->tmp->own_commit_scalar);
+
+       if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
+               goto fail;
+       if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
+               goto fail;
+
+       ret = 0;
+fail:
+       crypto_bignum_deinit(mask, 1);
+       return ret;
+}
+
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+                      const u8 *password, size_t password_len,
+                      struct sae_data *sae)
+{
+       if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
+                                         password_len) < 0)
+               return -1;
+       if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
+                                         password_len) < 0)
+               return -1;
+       if (sae_derive_commit(sae) < 0)
+               return -1;
+       return 0;
+}
+
+
+static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
+{
+       struct crypto_ec_point *K;
+       int ret = -1;
+
+       K = crypto_ec_point_init(sae->tmp->ec);
+       if (K == NULL)
+               goto fail;
+
+       /*
+        * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+        *                                        PEER-COMMIT-ELEMENT)))
+        * If K is identity element (point-at-infinity), reject
+        * k = F(K) (= x coordinate)
+        */
+
+       if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
+                               sae->peer_commit_scalar, K) < 0 ||
+           crypto_ec_point_add(sae->tmp->ec, K,
+                               sae->tmp->peer_commit_element_ecc, K) < 0 ||
+           crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
+           crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
+           crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+               goto fail;
+       }
+
+       wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+       ret = 0;
+fail:
+       crypto_ec_point_deinit(K, 1);
+       return ret;
+}
+
+
+static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
+{
+       struct crypto_bignum *K;
+       int ret = -1;
+
+       K = crypto_bignum_init();
+       if (K == NULL)
+               goto fail;
+
+       /*
+        * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+        *                                        PEER-COMMIT-ELEMENT)))
+        * If K is identity element (one), reject.
+        * k = F(K) (= x coordinate)
+        */
+
+       if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
+                                 sae->tmp->prime, K) < 0 ||
+           crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
+                                sae->tmp->prime, K) < 0 ||
+           crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
+           ||
+           crypto_bignum_is_one(K) ||
+           crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
+           0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+               goto fail;
+       }
+
+       wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+       ret = 0;
+fail:
+       crypto_bignum_deinit(K, 1);
+       return ret;
+}
+
+
+static int sae_derive_keys(struct sae_data *sae, const u8 *k)
+{
+       u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
+       u8 keyseed[SHA256_MAC_LEN];
+       u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+       struct crypto_bignum *tmp;
+       int ret = -1;
+
+       tmp = crypto_bignum_init();
+       if (tmp == NULL)
+               goto fail;
+
+       /* keyseed = H(<0>32, k)
+        * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+        *                      (commit-scalar + peer-commit-scalar) modulo r)
+        * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+        */
+
+       os_memset(null_key, 0, sizeof(null_key));
+       hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
+                   keyseed);
+       wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
+
+       crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
+                         tmp);
+       crypto_bignum_mod(tmp, sae->tmp->order, tmp);
+       crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
+       wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+       sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+                  val, sae->tmp->prime_len, keys, sizeof(keys));
+       os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
+       os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
+
+       ret = 0;
+fail:
+       crypto_bignum_deinit(tmp, 0);
+       return ret;
+}
+
+
+int sae_process_commit(struct sae_data *sae)
+{
+       u8 k[SAE_MAX_PRIME_LEN];
+       if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
+           (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
+           sae_derive_keys(sae, k) < 0)
+               return -1;
+       return 0;
+}
+
+
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+                     const struct wpabuf *token)
+{
+       u8 *pos;
+       wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
+       if (token)
+               wpabuf_put_buf(buf, token);
+       pos = wpabuf_put(buf, sae->tmp->prime_len);
+       crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+                            sae->tmp->prime_len, sae->tmp->prime_len);
+       wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
+                   pos, sae->tmp->prime_len);
+       if (sae->tmp->ec) {
+               pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
+               crypto_ec_point_to_bin(sae->tmp->ec,
+                                      sae->tmp->own_commit_element_ecc,
+                                      pos, pos + sae->tmp->prime_len);
+               wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
+                           pos, sae->tmp->prime_len);
+               wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
+                           pos + sae->tmp->prime_len, sae->tmp->prime_len);
+       } else {
+               pos = wpabuf_put(buf, sae->tmp->prime_len);
+               crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+                                    sae->tmp->prime_len, sae->tmp->prime_len);
+               wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
+                           pos, sae->tmp->prime_len);
+       }
+}
+
+
+static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
+                            u16 group)
+{
+       if (allowed_groups) {
+               int i;
+               for (i = 0; allowed_groups[i] >= 0; i++) {
+                       if (allowed_groups[i] == group)
+                               break;
+               }
+               if (allowed_groups[i] != group) {
+                       wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
+                                  "enabled in the current configuration",
+                                  group);
+                       return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+               }
+       }
+
+       if (sae->state == SAE_COMMITTED && group != sae->group) {
+               wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
+               return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+       }
+
+       if (group != sae->group && sae_set_group(sae, group) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+                          group);
+               return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+       }
+
+       if (sae->tmp->dh && !allowed_groups) {
+               wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
+                          "explicit configuration enabling it", group);
+               return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+       }
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
+                                  const u8 *end, const u8 **token,
+                                  size_t *token_len)
+{
+       if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
+               size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
+                                    sae->tmp->prime_len);
+               wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+               if (token)
+                       *token = *pos;
+               if (token_len)
+                       *token_len = tlen;
+               *pos += tlen;
+       } else {
+               if (token)
+                       *token = NULL;
+               if (token_len)
+                       *token_len = 0;
+       }
+}
+
+
+static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
+                                  const u8 *end)
+{
+       struct crypto_bignum *peer_scalar;
+
+       if (*pos + sae->tmp->prime_len > end) {
+               wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
+       if (peer_scalar == NULL)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+       /*
+        * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
+        * the peer and it is in Authenticated state, the new Commit Message
+        * shall be dropped if the peer-scalar is identical to the one used in
+        * the existing protocol instance.
+        */
+       if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
+           crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
+                          "peer-commit-scalar");
+               crypto_bignum_deinit(peer_scalar, 0);
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       /* 0 < scalar < r */
+       if (crypto_bignum_is_zero(peer_scalar) ||
+           crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
+               crypto_bignum_deinit(peer_scalar, 0);
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+
+       crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+       sae->peer_commit_scalar = peer_scalar;
+       wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
+                   *pos, sae->tmp->prime_len);
+       *pos += sae->tmp->prime_len;
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+                                       const u8 *end)
+{
+       u8 prime[SAE_MAX_ECC_PRIME_LEN];
+
+       if (pos + 2 * sae->tmp->prime_len > end) {
+               wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+                          "commit-element");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+                                sae->tmp->prime_len) < 0)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+       /* element x and y coordinates < p */
+       if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
+           os_memcmp(pos + sae->tmp->prime_len + sae->tmp->prime_len, prime,
+                     sae->tmp->prime_len) >= 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
+                          "element");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
+                   pos, sae->tmp->prime_len);
+       wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
+                   pos + sae->tmp->prime_len, sae->tmp->prime_len);
+
+       crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
+       sae->tmp->peer_commit_element_ecc =
+               crypto_ec_point_from_bin(sae->tmp->ec, pos);
+       if (sae->tmp->peer_commit_element_ecc == NULL)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+       if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
+                                        sae->tmp->peer_commit_element_ecc)) {
+               wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+                                       const u8 *end)
+{
+       struct crypto_bignum *res;
+
+       if (pos + sae->tmp->prime_len > end) {
+               wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+                          "commit-element");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+       wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+                   sae->tmp->prime_len);
+
+       crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
+       sae->tmp->peer_commit_element_ffc =
+               crypto_bignum_init_set(pos, sae->tmp->prime_len);
+       if (sae->tmp->peer_commit_element_ffc == NULL)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
+           crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
+           crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
+                             sae->tmp->prime) >= 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       /* scalar-op(r, ELEMENT) = 1 modulo p */
+       res = crypto_bignum_init();
+       if (res == NULL ||
+           crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
+                                 sae->tmp->order, sae->tmp->prime, res) < 0 ||
+           !crypto_bignum_is_one(res)) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
+               crypto_bignum_deinit(res, 0);
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+       crypto_bignum_deinit(res, 0);
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+                                   const u8 *end)
+{
+       if (sae->tmp->dh)
+               return sae_parse_commit_element_ffc(sae, pos, end);
+       return sae_parse_commit_element_ecc(sae, pos, end);
+}
+
+
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+                    const u8 **token, size_t *token_len, int *allowed_groups)
+{
+       const u8 *pos = data, *end = data + len;
+       u16 res;
+
+       /* Check Finite Cyclic Group */
+       if (pos + 2 > end)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
+       if (res != WLAN_STATUS_SUCCESS)
+               return res;
+       pos += 2;
+
+       /* Optional Anti-Clogging Token */
+       sae_parse_commit_token(sae, &pos, end, token, token_len);
+
+       /* commit-scalar */
+       res = sae_parse_commit_scalar(sae, &pos, end);
+       if (res != WLAN_STATUS_SUCCESS)
+               return res;
+
+       /* commit-element */
+       return sae_parse_commit_element(sae, pos, end);
+}
+
+
+static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+                          const struct crypto_bignum *scalar1,
+                          const u8 *element1, size_t element1_len,
+                          const struct crypto_bignum *scalar2,
+                          const u8 *element2, size_t element2_len,
+                          u8 *confirm)
+{
+       const u8 *addr[5];
+       size_t len[5];
+       u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
+
+       /* Confirm
+        * CN(key, X, Y, Z, ...) =
+        *    HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
+        * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
+        *              peer-commit-scalar, PEER-COMMIT-ELEMENT)
+        * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
+        *               PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
+        */
+       addr[0] = sc;
+       len[0] = 2;
+       crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+                            sae->tmp->prime_len);
+       addr[1] = scalar_b1;
+       len[1] = sae->tmp->prime_len;
+       addr[2] = element1;
+       len[2] = element1_len;
+       crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+                            sae->tmp->prime_len);
+       addr[3] = scalar_b2;
+       len[3] = sae->tmp->prime_len;
+       addr[4] = element2;
+       len[4] = element2_len;
+       hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
+                          confirm);
+}
+
+
+static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+                              const struct crypto_bignum *scalar1,
+                              const struct crypto_ec_point *element1,
+                              const struct crypto_bignum *scalar2,
+                              const struct crypto_ec_point *element2,
+                              u8 *confirm)
+{
+       u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
+       u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
+
+       crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+                              element_b1 + sae->tmp->prime_len);
+       crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+                              element_b2 + sae->tmp->prime_len);
+
+       sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
+                      scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+}
+
+
+static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+                              const struct crypto_bignum *scalar1,
+                              const struct crypto_bignum *element1,
+                              const struct crypto_bignum *scalar2,
+                              const struct crypto_bignum *element2,
+                              u8 *confirm)
+{
+       u8 element_b1[SAE_MAX_PRIME_LEN];
+       u8 element_b2[SAE_MAX_PRIME_LEN];
+
+       crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+                            sae->tmp->prime_len);
+       crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+                            sae->tmp->prime_len);
+
+       sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+                      scalar2, element_b2, sae->tmp->prime_len, confirm);
+}
+
+
+void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+{
+       const u8 *sc;
+
+       /* Send-Confirm */
+       sc = wpabuf_put(buf, 0);
+       wpabuf_put_le16(buf, sae->send_confirm);
+       sae->send_confirm++;
+
+       if (sae->tmp->ec)
+               sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+                                  sae->tmp->own_commit_element_ecc,
+                                  sae->peer_commit_scalar,
+                                  sae->tmp->peer_commit_element_ecc,
+                                  wpabuf_put(buf, SHA256_MAC_LEN));
+       else
+               sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+                                  sae->tmp->own_commit_element_ffc,
+                                  sae->peer_commit_scalar,
+                                  sae->tmp->peer_commit_element_ffc,
+                                  wpabuf_put(buf, SHA256_MAC_LEN));
+}
+
+
+int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
+{
+       u8 verifier[SHA256_MAC_LEN];
+
+       if (len < 2 + SHA256_MAC_LEN) {
+               wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
+
+       if (sae->tmp->ec)
+               sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+                                  sae->tmp->peer_commit_element_ecc,
+                                  sae->tmp->own_commit_scalar,
+                                  sae->tmp->own_commit_element_ecc,
+                                  verifier);
+       else
+               sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+                                  sae->tmp->peer_commit_element_ffc,
+                                  sae->tmp->own_commit_scalar,
+                                  sae->tmp->own_commit_element_ffc,
+                                  verifier);
+
+       if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
+               wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
+                           data + 2, SHA256_MAC_LEN);
+               wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
+                           verifier, SHA256_MAC_LEN);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/src/common/sae.h b/src/common/sae.h
new file mode 100644 (file)
index 0000000..d82a98e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SAE_H
+#define SAE_H
+
+#define SAE_KCK_LEN 32
+#define SAE_PMK_LEN 32
+#define SAE_PMKID_LEN 16
+#define SAE_KEYSEED_KEY_LEN 32
+#define SAE_MAX_PRIME_LEN 512
+#define SAE_MAX_ECC_PRIME_LEN 66
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+
+struct sae_temporary_data {
+       u8 kck[SAE_KCK_LEN];
+       struct crypto_bignum *own_commit_scalar;
+       struct crypto_bignum *own_commit_element_ffc;
+       struct crypto_ec_point *own_commit_element_ecc;
+       struct crypto_bignum *peer_commit_element_ffc;
+       struct crypto_ec_point *peer_commit_element_ecc;
+       struct crypto_ec_point *pwe_ecc;
+       struct crypto_bignum *pwe_ffc;
+       struct crypto_bignum *sae_rand;
+       struct crypto_ec *ec;
+       int prime_len;
+       const struct dh_group *dh;
+       const struct crypto_bignum *prime;
+       const struct crypto_bignum *order;
+       struct crypto_bignum *prime_buf;
+       struct crypto_bignum *order_buf;
+};
+
+struct sae_data {
+       enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+       u16 send_confirm;
+       u8 pmk[SAE_PMK_LEN];
+       struct crypto_bignum *peer_commit_scalar;
+       int group;
+       struct sae_temporary_data *tmp;
+};
+
+int sae_set_group(struct sae_data *sae, int group);
+void sae_clear_temp_data(struct sae_data *sae);
+void sae_clear_data(struct sae_data *sae);
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+                      const u8 *password, size_t password_len,
+                      struct sae_data *sae);
+int sae_process_commit(struct sae_data *sae);
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+                     const struct wpabuf *token);
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+                    const u8 **token, size_t *token_len, int *allowed_groups);
+void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
+int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
+
+#endif /* SAE_H */
index 7afba48..2faa8c7 100644 (file)
@@ -5,6 +5,6 @@
 #define VERSION_STR_POSTFIX ""
 #endif /* VERSION_STR_POSTFIX */
 
-#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX
+#define VERSION_STR "2.1-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
index 24a61e4..c3afbfd 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -49,8 +43,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
        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;
@@ -339,7 +335,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
 #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)
@@ -356,6 +351,8 @@ static int rsn_selector_to_bitfield(const u8 *s)
        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;
 }
 
@@ -378,9 +375,14 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
        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 */
 
 
 /**
@@ -393,7 +395,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 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;
@@ -547,9 +548,6 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
        }
 
        return 0;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -912,6 +910,8 @@ const char * wpa_cipher_txt(int cipher)
                return "CCMP";
        case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
                return "CCMP+TKIP";
+       case WPA_CIPHER_GCMP:
+               return "GCMP";
        default:
                return "UNKNOWN";
        }
@@ -1073,3 +1073,305 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
        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;
+}
+
+
+enum wpa_cipher wpa_cipher_to_suite_driver(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;
+       }
+}
+
+
+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;
+}
+
+
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
+{
+       if (ciphers & WPA_CIPHER_CCMP)
+               return WPA_CIPHER_CCMP;
+       if (ciphers & WPA_CIPHER_GCMP)
+               return WPA_CIPHER_GCMP;
+       if (ciphers & WPA_CIPHER_TKIP)
+               return WPA_CIPHER_TKIP;
+       if (none_allowed && (ciphers & WPA_CIPHER_NONE))
+               return WPA_CIPHER_NONE;
+       return -1;
+}
+
+
+int wpa_pick_group_cipher(int ciphers)
+{
+       if (ciphers & WPA_CIPHER_CCMP)
+               return WPA_CIPHER_CCMP;
+       if (ciphers & WPA_CIPHER_GCMP)
+               return WPA_CIPHER_GCMP;
+       if (ciphers & WPA_CIPHER_TKIP)
+               return WPA_CIPHER_TKIP;
+       if (ciphers & WPA_CIPHER_WEP104)
+               return WPA_CIPHER_WEP104;
+       if (ciphers & WPA_CIPHER_WEP40)
+               return WPA_CIPHER_WEP40;
+       return -1;
+}
+
+
+int wpa_parse_cipher(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 {
+                       os_free(buf);
+                       return -1;
+               }
+
+               if (last)
+                       break;
+               start = end + 1;
+       }
+       os_free(buf);
+
+       return val;
+}
+
+
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
+{
+       char *pos = start;
+       int ret;
+
+       if (ciphers & WPA_CIPHER_CCMP) {
+               ret = os_snprintf(pos, end - pos, "%sCCMP",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+       if (ciphers & WPA_CIPHER_GCMP) {
+               ret = os_snprintf(pos, end - pos, "%sGCMP",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+       if (ciphers & WPA_CIPHER_TKIP) {
+               ret = os_snprintf(pos, end - pos, "%sTKIP",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+       if (ciphers & WPA_CIPHER_WEP104) {
+               ret = os_snprintf(pos, end - pos, "%sWEP104",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+       if (ciphers & WPA_CIPHER_WEP40) {
+               ret = os_snprintf(pos, end - pos, "%sWEP40",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+       if (ciphers & WPA_CIPHER_NONE) {
+               ret = os_snprintf(pos, end - pos, "%sNONE",
+                                 pos == start ? "" : delim);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       return pos - start;
+}
+
+
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
+{
+       int pairwise = 0;
+
+       /* Select group cipher based on the enabled pairwise cipher suites */
+       if (wpa & 1)
+               pairwise |= wpa_pairwise;
+       if (wpa & 2)
+               pairwise |= rsn_pairwise;
+
+       if (pairwise & WPA_CIPHER_TKIP)
+               return WPA_CIPHER_TKIP;
+       if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
+               return WPA_CIPHER_GCMP;
+       return WPA_CIPHER_CCMP;
+}
index 69437a7..2d63662 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_COMMON_H
 #define WPA_GMK_LEN 32
 #define WPA_GTK_MAX_LEN 32
 
+#define WPA_ALLOWED_PAIRWISE_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)
+#define WPA_ALLOWED_GROUP_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
+WPA_CIPHER_WEP40)
+
 #define WPA_SELECTOR_LEN 4
 #define WPA_VERSION 1
 #define RSN_SELECTOR_LEN 4
@@ -38,6 +38,7 @@
 #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)
@@ -57,6 +58,9 @@
 #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)
@@ -70,6 +74,7 @@
 #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.
@@ -89,6 +94,9 @@
 #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)
 
@@ -381,4 +389,18 @@ struct wpa_ft_ies {
 
 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);
+enum wpa_cipher wpa_cipher_to_suite_driver(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);
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed);
+int wpa_pick_group_cipher(int ciphers);
+int wpa_parse_cipher(const char *value);
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+
 #endif /* WPA_COMMON_H */
index 3b25f77..d9a7509 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd control interface library
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 
 #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>
@@ -50,6 +49,8 @@ struct wpa_ctrl {
        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;
@@ -79,6 +80,10 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
        int ret;
        size_t res;
        int tries = 0;
+       int flags;
+
+       if (ctrl_path == NULL)
+               return NULL;
 
        ctrl = os_malloc(sizeof(*ctrl));
        if (ctrl == NULL)
@@ -124,13 +129,27 @@ try_again:
 #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 (os_strncmp(ctrl_path, "@android:", 9) == 0) {
+               if (socket_local_client_connect(
+                           ctrl->s, ctrl_path + 9,
+                           ANDROID_SOCKET_NAMESPACE_RESERVED,
+                           SOCK_DGRAM) < 0) {
+                       close(ctrl->s);
+                       unlink(ctrl->local.sun_path);
+                       os_free(ctrl);
+                       return NULL;
+               }
+               return ctrl;
+       }
+
        /*
         * 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 != '/') {
+       if (*ctrl_path != '/') {
                char buf[21];
                os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
                if (socket_local_client_connect(
@@ -147,12 +166,18 @@ try_again:
 #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 (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
+               ctrl->dest.sun_path[0] = '\0';
+               os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
+                          sizeof(ctrl->dest.sun_path) - 1);
+       } else {
+               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) {
@@ -162,6 +187,19 @@ try_again:
                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;
 }
 
@@ -236,6 +274,9 @@ 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)
@@ -250,7 +291,11 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
        }
 
        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);
@@ -261,10 +306,48 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
        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;
        }
@@ -275,14 +358,31 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                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);
 }
 
@@ -295,6 +395,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_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;
@@ -321,7 +422,30 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
                _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;
        }
index 6cd9de5..0ab4b7f 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd control interface library
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_CTRL_H
@@ -50,10 +44,16 @@ extern "C" {
 #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 status */
+#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
 /** 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 */
@@ -122,16 +122,24 @@ extern "C" {
 #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 "
+
+/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
+#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
 
 #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 "
@@ -143,6 +151,31 @@ extern "C" {
 #define AP_STA_CONNECTED "AP-STA-CONNECTED "
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
 
+#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
+#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
+
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL               0xFFFDFFFF
+#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)
+#define WPA_BSS_MASK_DELIM             BIT(17)
+
 
 /* wpa_supplicant/hostapd control interface access */
 
@@ -268,6 +301,8 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
  */
 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
@@ -280,8 +315,11 @@ 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 */
 
 
diff --git a/src/crypto/.gitignore b/src/crypto/.gitignore
new file mode 100644 (file)
index 0000000..ee60604
--- /dev/null
@@ -0,0 +1 @@
+libcrypto.a
index b221dd4..a605a65 100644 (file)
@@ -16,9 +16,11 @@ 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 \
@@ -31,16 +33,17 @@ LIB_OBJS= \
        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-prf.o \
        sha1-tlsprf.o \
        sha1-tprf.o \
        sha256.o \
+       sha256-prf.o \
        sha256-tlsprf.o \
        sha256-internal.o
 
index bd74769..2833cfc 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/src/crypto/aes-ccm.c b/src/crypto/aes-ccm.c
new file mode 100644 (file)
index 0000000..d14670d
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Counter with CBC-MAC (CCM) with AES
+ *
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "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;
+}
index 468f877..d4d874d 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index d5c3971..21941c6 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 8f35caa..a521621 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/src/crypto/aes-gcm.c b/src/crypto/aes-gcm.c
new file mode 100644 (file)
index 0000000..3d91c71
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Galois/Counter Mode (GCM) and GMAC with AES
+ *
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "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);
+}
index a0fc45b..720c703 100644 (file)
@@ -2,23 +2,16 @@
  * 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@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
  *
  * @return     the number of rounds for the given cipher key size.
  */
-static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits)
 {
-       int Nr = 10, i, j;
+       int Nr, i, j;
        u32 temp;
 
        /* expand the cipher key: */
-       rijndaelKeySetupEnc(rk, cipherKey);
+       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;
@@ -57,24 +52,30 @@ static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
                                TD3_(TE4((rk[j]      ) & 0xff));
                }
        }
+
+       return Nr;
 }
 
 void * aes_decrypt_init(const u8 *key, size_t len)
 {
        u32 *rk;
-       if (len != 16)
-               return NULL;
+       int res;
        rk = os_malloc(AES_PRIV_SIZE);
        if (rk == NULL)
                return NULL;
-       rijndaelKeySetupDec(rk, key);
+       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*/], const u8 ct[16], u8 pt[16])
+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;
-       const int Nr = 10;
 #ifndef FULL_UNROLL
        int r;
 #endif /* ?FULL_UNROLL */
@@ -105,6 +106,14 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
        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;
 
@@ -140,7 +149,8 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
 
 void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
 {
-       rijndaelDecrypt(ctx, crypt, plain);
+       u32 *rk = ctx;
+       rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain);
 }
 
 
index 8726aa7..f3c61b8 100644 (file)
@@ -2,23 +2,16 @@
  * 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@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "crypto.h"
 #include "aes_i.h"
 
-static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+static void rijndaelEncrypt(const u32 rk[], int Nr, 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 */
@@ -61,6 +53,14 @@ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
        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;
 
@@ -98,19 +98,24 @@ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
 void * aes_encrypt_init(const u8 *key, size_t len)
 {
        u32 *rk;
-       if (len != 16)
-               return NULL;
+       int res;
        rk = os_malloc(AES_PRIV_SIZE);
        if (rk == NULL)
                return NULL;
-       rijndaelKeySetupEnc(rk, key);
+       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)
 {
-       rijndaelEncrypt(ctx, plain, crypt);
+       u32 *rk = ctx;
+       rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
 }
 
 
index 4161220..bd4535d 100644 (file)
@@ -2,23 +2,16 @@
  * 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@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -783,7 +776,7 @@ const u8 rcons[] = {
  *
  * @return     the number of rounds for the given cipher key size.
  */
-void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits)
 {
        int i;
        u32 temp;
@@ -792,14 +785,61 @@ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 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;
+
+       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;
 }
index f775296..27895eb 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f233ffa..9dd5160 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 28d0c89..89d6f94 100644 (file)
@@ -3,14 +3,8 @@
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index ba384a9..2de59e0 100644 (file)
@@ -2,14 +2,8 @@
  * AES functions
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AES_H
index 6b40bc7..54375cf 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * AES (Rijndael) cipher
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AES_I_H
@@ -50,6 +44,10 @@ extern const u8 rcons[10];
 #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]
@@ -86,6 +84,10 @@ static inline u32 rotr(u32 val, int bits)
 #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]
@@ -115,8 +117,9 @@ static inline u32 rotr(u32 val, int bits)
 (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
 #endif
 
-#define AES_PRIV_SIZE (4 * 44)
+#define AES_PRIV_SIZE (4 * 4 * 15 + 4)
+#define AES_PRIV_NR_POS (4 * 15)
 
-void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]);
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits);
 
 #endif /* AES_I_H */
index 4b1c7b0..0433c04 100644 (file)
@@ -6,17 +6,13 @@
  * - AES-128 CTR mode encryption
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
+ * - AES-GCM
+ * - AES-CCM
  *
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AES_WRAP_H
@@ -44,5 +40,25 @@ 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 */
index 6dca191..9bccaaa 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for crypto libraries
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -47,21 +41,6 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
  */
 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
@@ -467,4 +446,340 @@ int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
 int rc4_skip(const u8 *key, size_t keylen, size_t skip,
             u8 *data, size_t data_len);
 
+/**
+ * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * @buf: Buffer for data
+ * @len: Number of bytes to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the PRNG does not have enough entropy to ensure unpredictable byte
+ * sequence, this functions must return -1.
+ */
+int crypto_get_random(void *buf, size_t len);
+
+
+/**
+ * struct crypto_bignum - bignum
+ *
+ * Internal data structure for bignum implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_bignum;
+
+/**
+ * crypto_bignum_init - Allocate memory for bignum
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init(void);
+
+/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value
+ * @buf: Buffer with unsigned binary value
+ * @len: Length of buf in octets
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
+
+/**
+ * crypto_bignum_deinit - Free bignum
+ * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
+ * @clear: Whether to clear the value from memory
+ */
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear);
+
+/**
+ * crypto_bignum_to_bin - Set binary buffer to unsigned bignum
+ * @a: Bignum
+ * @buf: Buffer for the binary number
+ * @len: Length of @buf in octets
+ * @padlen: Length in octets to pad the result to or 0 to indicate no padding
+ * Returns: Number of octets written on success, -1 on failure
+ */
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+                        u8 *buf, size_t buflen, size_t padlen);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_add(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mod - c = a % b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mod(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c)
+ * @a: Bignum; base
+ * @b: Bignum; exponent
+ * @c: Bignum; modulus
+ * @d: Bignum; used to store the result of a^b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+                         const struct crypto_bignum *b,
+                         const struct crypto_bignum *c,
+                         struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_rshift - b = a >> n
+ * @a: Bignum
+ * @n: Number of bits to shift
+ * @b: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+                        struct crypto_bignum *b);
+
+/**
+ * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+                         const struct crypto_bignum *b,
+                         struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_sub - c = a - b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a - b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sub(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_div - c = a / b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a / b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_div(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mulmod - d = a * b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a * b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+                        const struct crypto_bignum *b,
+                        const struct crypto_bignum *c,
+                        struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_cmp - Compare two bignums
+ * @a: Bignum
+ * @b: Bignum
+ * Returns: -1 if a < b, 0 if a == b, or 1 if a > b
+ */
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b);
+
+/**
+ * crypto_bignum_bits - Get size of a bignum in bits
+ * @a: Bignum
+ * Returns: Number of bits in the bignum
+ */
+int crypto_bignum_bits(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_zero - Is the given bignum zero
+ * @a: Bignum
+ * Returns: 1 if @a is zero or 0 if not
+ */
+int crypto_bignum_is_zero(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_one - Is the given bignum one
+ * @a: Bignum
+ * Returns: 1 if @a is one or 0 if not
+ */
+int crypto_bignum_is_one(const struct crypto_bignum *a);
+
+/**
+ * struct crypto_ec - Elliptic curve context
+ *
+ * Internal data structure for EC implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_ec;
+
+/**
+ * crypto_ec_init - Initialize elliptic curve context
+ * @group: Identifying number for the ECC group (IANA "Group Description"
+ *     attribute registrty for RFC 2409)
+ * Returns: Pointer to EC context or %NULL on failure
+ */
+struct crypto_ec * crypto_ec_init(int group);
+
+/**
+ * crypto_ec_deinit - Deinitialize elliptic curve context
+ * @e: EC context from crypto_ec_init()
+ */
+void crypto_ec_deinit(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len - Get length of the prime in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group
+ */
+size_t crypto_ec_prime_len(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len_bits - Get length of the prime in bits
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group in bits
+ */
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_prime - Get prime defining an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Prime (bignum) defining the group
+ */
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_order - Get order of an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Order (bignum) of the group
+ */
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+
+/**
+ * struct crypto_ec_point - Elliptic curve point
+ *
+ * Internal data structure for EC implementation to represent a point. The
+ * contents is specific to the used crypto library.
+ */
+struct crypto_ec_point;
+
+/**
+ * crypto_ec_point_init - Initialize data for an EC point
+ * @e: EC context from crypto_ec_init()
+ * Returns: Pointer to EC point data or %NULL on failure
+ */
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
+
+/**
+ * crypto_ec_point_deinit - Deinitialize EC point data
+ * @p: EC point data from crypto_ec_point_init()
+ * @clear: Whether to clear the EC point value from memory
+ */
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
+
+/**
+ * crypto_ec_point_to_bin - Write EC point value as binary data
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data from crypto_ec_point_init()
+ * @x: Buffer for writing the binary data for x coordinate or %NULL if not used
+ * @y: Buffer for writing the binary data for y coordinate or %NULL if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to write an EC point as binary data in a format
+ * that has the x and y coordinates in big endian byte order fields padded to
+ * the length of the prime defining the group.
+ */
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+                          const struct crypto_ec_point *point, u8 *x, u8 *y);
+
+/**
+ * crypto_ec_point_from_bin - Create EC point from binary data
+ * @e: EC context from crypto_ec_init()
+ * @val: Binary data to read the EC point from
+ * Returns: Pointer to EC point data or %NULL on failure
+ *
+ * This function readers x and y coordinates of the EC point from the provided
+ * buffer assuming the values are in big endian byte order with fields padded to
+ * the length of the prime defining the group.
+ */
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+                                                 const u8 *val);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @e: EC context from crypto_ec_init()
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+                       const struct crypto_ec_point *b,
+                       struct crypto_ec_point *c);
+
+/**
+ * crypto_bignum_mul - res = b * p
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * @b: Bignum
+ * @res: EC point; used to store the result of b * p
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+                       const struct crypto_bignum *b,
+                       struct crypto_ec_point *res);
+
+/**
+ * crypto_ec_point_invert - Compute inverse of an EC point
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to invert (and result of the operation)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to use for the returning the result
+ * @x: x coordinate
+ * @y_bit: y-bit (0 or 1) for selecting the y value to use
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+                                 struct crypto_ec_point *p,
+                                 const struct crypto_bignum *x, int y_bit);
+
+/**
+ * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is the neutral element of the group or
+ *     0 if not
+ */
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+                                  const struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_is_on_curve - Check whether EC point is on curve
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is on the curve or 0 if not
+ */
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+                               const struct crypto_ec_point *p);
+
 #endif /* CRYPTO_H */
index 2a8d200..55a069b 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper for Microsoft CryptoAPI
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0998cca..0dfd54d 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / wrapper functions for libgcrypt
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 75134f0..ad0930a 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper for internal crypto implementation - Cipher wrappers
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -30,7 +24,6 @@ struct crypto_cipher {
                } rc4;
                struct {
                        u8 cbc[32];
-                       size_t block_size;
                        void *ctx_enc;
                        void *ctx_dec;
                } aes;
@@ -69,10 +62,6 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
                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);
@@ -84,8 +73,7 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
                        os_free(ctx);
                        return NULL;
                }
-               ctx->u.aes.block_size = key_len;
-               os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size);
+               os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
                break;
        case CRYPTO_CIPHER_ALG_3DES:
                if (key_len != 24) {
@@ -126,18 +114,17 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
                ctx->u.rc4.used_bytes += len;
                break;
        case CRYPTO_CIPHER_ALG_AES:
-               if (len % ctx->u.aes.block_size)
+               if (len % AES_BLOCK_SIZE)
                        return -1;
-               blocks = len / ctx->u.aes.block_size;
+               blocks = len / AES_BLOCK_SIZE;
                for (i = 0; i < blocks; i++) {
-                       for (j = 0; j < ctx->u.aes.block_size; j++)
+                       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,
-                                 ctx->u.aes.block_size);
-                       plain += ctx->u.aes.block_size;
-                       crypt += ctx->u.aes.block_size;
+                       os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
+                       plain += AES_BLOCK_SIZE;
+                       crypt += AES_BLOCK_SIZE;
                }
                break;
        case CRYPTO_CIPHER_ALG_3DES:
@@ -191,17 +178,17 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
                ctx->u.rc4.used_bytes += len;
                break;
        case CRYPTO_CIPHER_ALG_AES:
-               if (len % ctx->u.aes.block_size)
+               if (len % AES_BLOCK_SIZE)
                        return -1;
-               blocks = len / ctx->u.aes.block_size;
+               blocks = len / AES_BLOCK_SIZE;
                for (i = 0; i < blocks; i++) {
-                       os_memcpy(tmp, crypt, ctx->u.aes.block_size);
+                       os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
                        aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
-                       for (j = 0; j < ctx->u.aes.block_size; j++)
+                       for (j = 0; j < 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;
+                       os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
+                       plain += AES_BLOCK_SIZE;
+                       crypt += AES_BLOCK_SIZE;
                }
                break;
        case CRYPTO_CIPHER_ALG_3DES:
index 3124742..9dcabb9 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper for internal crypto implementation - modexp
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 7f0a5cf..54209fa 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper for internal crypto implementation - RSA parts
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 9362fe1..f3602da 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper for internal crypto implementation
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 52b67a7..a55edd1 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 9f43775..011f3f3 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Empty template functions for crypto wrapper
  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index fee4195..acd0a55 100644 (file)
@@ -2,14 +2,8 @@
  * Crypto wrapper functions for NSS
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 08c98af..5215c00 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for OpenSSL libcrypto
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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 */
+#ifdef CONFIG_ECC
+#include <openssl/ec.h>
+#endif /* CONFIG_ECC */
 
 #include "common.h"
 #include "wpabuf.h"
@@ -74,21 +76,14 @@ static BIGNUM * get_group5_prime(void)
 #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)
+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);
-#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));
@@ -114,7 +109,7 @@ static int openssl_digest_vector(const EVP_MD *type, int non_fips,
 
 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);
+       return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
 }
 
 
@@ -178,22 +173,13 @@ out:
 
 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);
+       return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
 }
-#endif /* CONFIG_FIPS */
 
 
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-       return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
+       return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
 }
 
 
@@ -201,60 +187,124 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 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);
+       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)
 {
-       AES_KEY *ak;
-       ak = os_malloc(sizeof(*ak));
-       if (ak == NULL)
+       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;
-       if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
-               os_free(ak);
+       EVP_CIPHER_CTX_init(ctx);
+       if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+               os_free(ctx);
                return NULL;
        }
-       return ak;
+       EVP_CIPHER_CTX_set_padding(ctx, 0);
+       return ctx;
 }
 
 
 void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
 {
-       AES_encrypt(plain, crypt, ctx);
+       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)
 {
-       os_free(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)
 {
-       AES_KEY *ak;
-       ak = os_malloc(sizeof(*ak));
-       if (ak == NULL)
+       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;
-       if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
-               os_free(ak);
+       EVP_CIPHER_CTX_init(ctx);
+       if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+               os_free(ctx);
                return NULL;
        }
-       return ak;
+       EVP_CIPHER_CTX_set_padding(ctx, 0);
+       return ctx;
 }
 
 
 void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
 {
-       AES_decrypt(crypt, plain, ctx);
+       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);
 }
 
@@ -458,6 +508,41 @@ err:
 }
 
 
+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)
 {
@@ -503,3 +588,646 @@ void dh5_free(void *ctx)
        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 */
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+       return (struct crypto_bignum *) BN_new();
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+       BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+       return (struct crypto_bignum *) bn;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+       if (clear)
+               BN_clear_free((BIGNUM *) n);
+       else
+               BN_free((BIGNUM *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+                        u8 *buf, size_t buflen, size_t padlen)
+{
+       int num_bytes, offset;
+
+       if (padlen > buflen)
+               return -1;
+
+       num_bytes = BN_num_bytes((const BIGNUM *) a);
+       if ((size_t) num_bytes > buflen)
+               return -1;
+       if (padlen > (size_t) num_bytes)
+               offset = padlen - num_bytes;
+       else
+               offset = 0;
+
+       os_memset(buf, 0, offset);
+       BN_bn2bin((const BIGNUM *) a, buf + offset);
+
+       return num_bytes + offset;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c)
+{
+       return BN_add((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+               0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c)
+{
+       int res;
+       BN_CTX *bnctx;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -1;
+       res = BN_mod((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+                    bnctx);
+       BN_CTX_free(bnctx);
+
+       return res ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+                         const struct crypto_bignum *b,
+                         const struct crypto_bignum *c,
+                         struct crypto_bignum *d)
+{
+       int res;
+       BN_CTX *bnctx;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -1;
+       res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+                        (const BIGNUM *) c, bnctx);
+       BN_CTX_free(bnctx);
+
+       return res ? 0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+                        struct crypto_bignum *b)
+{
+       return BN_rshift((BIGNUM *) b, (const BIGNUM *) a, n) ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+                         const struct crypto_bignum *b,
+                         struct crypto_bignum *c)
+{
+       BIGNUM *res;
+       BN_CTX *bnctx;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -1;
+       res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
+                            (const BIGNUM *) b, bnctx);
+       BN_CTX_free(bnctx);
+
+       return res ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c)
+{
+       return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+               0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b,
+                     struct crypto_bignum *c)
+{
+       int res;
+
+       BN_CTX *bnctx;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -1;
+       res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
+                    (const BIGNUM *) b, bnctx);
+       BN_CTX_free(bnctx);
+
+       return res ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+                        const struct crypto_bignum *b,
+                        const struct crypto_bignum *c,
+                        struct crypto_bignum *d)
+{
+       int res;
+
+       BN_CTX *bnctx;
+
+       bnctx = BN_CTX_new();
+       if (bnctx == NULL)
+               return -1;
+       res = BN_mod_mul((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+                        (const BIGNUM *) c, bnctx);
+       BN_CTX_free(bnctx);
+
+       return res ? 0 : -1;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+                     const struct crypto_bignum *b)
+{
+       return BN_cmp((const BIGNUM *) a, (const BIGNUM *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+       return BN_num_bits((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+       return BN_is_zero((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+       return BN_is_one((const BIGNUM *) a);
+}
+
+
+#ifdef CONFIG_ECC
+
+struct crypto_ec {
+       EC_GROUP *group;
+       BN_CTX *bnctx;
+       BIGNUM *prime;
+       BIGNUM *order;
+};
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+       struct crypto_ec *e;
+       int nid;
+
+       /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+       switch (group) {
+       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:
+               return NULL;
+       }
+
+       e = os_zalloc(sizeof(*e));
+       if (e == NULL)
+               return NULL;
+
+       e->bnctx = BN_CTX_new();
+       e->group = EC_GROUP_new_by_curve_name(nid);
+       e->prime = BN_new();
+       e->order = BN_new();
+       if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
+           e->order == NULL ||
+           !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+           !EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
+               crypto_ec_deinit(e);
+               e = NULL;
+       }
+
+       return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec *e)
+{
+       if (e == NULL)
+               return;
+       BN_free(e->order);
+       EC_GROUP_free(e->group);
+       BN_CTX_free(e->bnctx);
+       os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+       if (e == NULL)
+               return NULL;
+       return (struct crypto_ec_point *) EC_POINT_new(e->group);
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+       return BN_num_bytes(e->prime);
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+       return BN_num_bits(e->prime);
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+       return (const struct crypto_bignum *) e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+       return (const struct crypto_bignum *) e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+       if (clear)
+               EC_POINT_clear_free((EC_POINT *) p);
+       else
+               EC_POINT_free((EC_POINT *) p);
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+                          const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+       BIGNUM *x_bn, *y_bn;
+       int ret = -1;
+       int len = BN_num_bytes(e->prime);
+
+       x_bn = BN_new();
+       y_bn = BN_new();
+
+       if (x_bn && y_bn &&
+           EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
+                                               x_bn, y_bn, e->bnctx)) {
+               if (x) {
+                       crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
+                                            x, len, len);
+               }
+               if (y) {
+                       crypto_bignum_to_bin((struct crypto_bignum *) y_bn,
+                                            y, len, len);
+               }
+               ret = 0;
+       }
+
+       BN_free(x_bn);
+       BN_free(y_bn);
+       return ret;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+                                                 const u8 *val)
+{
+       BIGNUM *x, *y;
+       EC_POINT *elem;
+       int len = BN_num_bytes(e->prime);
+
+       x = BN_bin2bn(val, len, NULL);
+       y = BN_bin2bn(val + len, len, NULL);
+       elem = EC_POINT_new(e->group);
+       if (x == NULL || y == NULL || elem == NULL) {
+               BN_free(x);
+               BN_free(y);
+               EC_POINT_free(elem);
+               return NULL;
+       }
+
+       if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
+                                                e->bnctx)) {
+               EC_POINT_free(elem);
+               elem = NULL;
+       }
+
+       BN_free(x);
+       BN_free(y);
+
+       return (struct crypto_ec_point *) elem;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+                       const struct crypto_ec_point *b,
+                       struct crypto_ec_point *c)
+{
+       return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
+                           (const EC_POINT *) b, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+                       const struct crypto_bignum *b,
+                       struct crypto_ec_point *res)
+{
+       return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
+                           (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
+               ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+       return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+                                 struct crypto_ec_point *p,
+                                 const struct crypto_bignum *x, int y_bit)
+{
+       if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
+                                                    (const BIGNUM *) x, y_bit,
+                                                    e->bnctx) ||
+           !EC_POINT_is_on_curve(e->group, (EC_POINT *) p, e->bnctx))
+               return -1;
+       return 0;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+                                  const struct crypto_ec_point *p)
+{
+       return EC_POINT_is_at_infinity(e->group, (const EC_POINT *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+                               const struct crypto_ec_point *p)
+{
+       return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
+}
+
+#endif /* CONFIG_ECC */
index ccea950..dec39ef 100644 (file)
@@ -4,14 +4,8 @@
  * Modifications to LibTomCrypt implementation:
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 6f27414..c9563d2 100644 (file)
@@ -2,14 +2,8 @@
  * DES and 3DES-EDE ciphers
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DES_I_H
index 2a67d99..ccdbfc8 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -28,6 +22,12 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 }
 
 
+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)
 {
index 595f111..abee8ea 100644 (file)
@@ -1,21 +1,16 @@
 /*
  * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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);
index e5b7d4c..3a675df 100644 (file)
@@ -2,14 +2,8 @@
  * Diffie-Hellman groups
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -41,6 +35,20 @@ static const u8 dh_group1_prime[96] = {
        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group1_order[96] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1D, 0x1B, 0x10,
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 /* RFC 4306, B.2. Group 2 - 1024 Bit MODP
  * Generator: 2
@@ -65,6 +73,24 @@ static const u8 dh_group2_prime[128] = {
        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group2_order[128] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 #endif /* ALL_DH_GROUPS */
 
@@ -99,6 +125,32 @@ static const u8 dh_group5_prime[192] = {
        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group5_order[192] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x11, 0xB9, 0x93,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 #ifdef ALL_DH_GROUPS
 
@@ -141,6 +193,40 @@ static const u8 dh_group14_prime[256] = {
        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group14_order[256] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+       0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+       0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+       0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+       0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+       0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+       0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+       0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+       0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34,
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 /* RFC 3526, 4. Group 15 - 3072 Bit MODP
  * Generator: 2
@@ -197,6 +283,56 @@ static const u8 dh_group15_prime[384] = {
        0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group15_order[384] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+       0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+       0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+       0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+       0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+       0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+       0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+       0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+       0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+       0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+       0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+       0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+       0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+       0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+       0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+       0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+       0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+       0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+       0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+       0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+       0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+       0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+       0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+       0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+       0x25, 0xC1, 0x68, 0x90, 0x54, 0x9D, 0x69, 0x65,
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 /* RFC 3526, 5. Group 16 - 4096 Bit MODP
  * Generator: 2
@@ -269,6 +405,72 @@ static const u8 dh_group16_prime[512] = {
        0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group16_order[512] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+       0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+       0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+       0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+       0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+       0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+       0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+       0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+       0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+       0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+       0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+       0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+       0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+       0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+       0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+       0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+       0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+       0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+       0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+       0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+       0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+       0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+       0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+       0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+       0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+       0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+       0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+       0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+       0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+       0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+       0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+       0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+       0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+       0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+       0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+       0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+       0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+       0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+       0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+       0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+       0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 /* RFC 3526, 6. Group 17 - 6144 Bit MODP
  * Generator: 2
@@ -373,6 +575,104 @@ static const u8 dh_group17_prime[768] = {
        0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group17_order[768] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+       0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+       0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+       0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+       0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+       0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+       0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+       0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+       0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+       0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+       0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+       0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+       0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+       0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+       0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+       0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+       0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+       0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+       0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+       0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+       0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+       0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+       0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+       0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+       0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+       0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+       0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+       0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+       0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+       0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+       0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+       0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+       0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+       0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+       0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+       0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+       0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+       0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+       0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+       0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+       0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+       0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+       0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+       0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+       0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+       0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+       0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+       0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+       0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+       0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+       0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+       0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+       0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+       0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+       0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+       0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+       0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+       0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+       0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+       0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+       0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+       0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+       0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+       0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+       0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+       0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+       0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+       0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+       0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+       0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+       0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+       0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+       0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xE6, 0x20, 0x12,
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
 
 /* RFC 3526, 7. Group 18 - 8192 Bit MODP
  * Generator: 2
@@ -509,25 +809,363 @@ static const u8 dh_group18_prime[1024] = {
        0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 };
+static const u8 dh_group18_order[1024] = {
+       0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+       0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+       0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+       0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+       0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+       0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+       0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+       0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+       0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+       0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+       0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+       0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+       0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+       0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+       0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+       0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+       0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+       0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+       0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+       0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+       0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+       0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+       0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+       0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+       0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+       0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+       0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+       0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+       0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+       0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+       0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+       0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+       0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+       0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+       0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+       0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+       0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+       0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+       0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+       0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+       0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+       0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+       0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+       0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+       0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+       0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+       0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+       0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+       0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+       0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+       0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+       0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+       0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+       0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+       0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+       0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+       0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+       0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+       0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+       0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+       0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+       0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+       0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+       0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+       0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+       0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+       0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+       0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+       0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+       0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+       0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+       0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+       0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+       0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+       0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+       0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+       0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+       0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+       0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+       0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+       0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+       0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+       0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+       0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+       0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+       0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+       0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+       0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+       0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+       0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+       0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+       0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+       0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+       0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xDF, 0x08, 0xAC,
+       0xBA, 0x51, 0xC9, 0x37, 0x89, 0x7F, 0x72, 0xF2,
+       0x1C, 0x3B, 0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6,
+       0x6C, 0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD,
+       0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9, 0x80,
+       0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E, 0x23, 0xF6,
+       0x92, 0xBB, 0x7B, 0x49, 0xB5, 0xD2, 0x12, 0x33,
+       0x1D, 0x55, 0xB1, 0xCE, 0x2D, 0x72, 0x7A, 0xB4,
+       0x1A, 0x11, 0xDA, 0x3A, 0x15, 0xF8, 0xE4, 0xBC,
+       0x11, 0xC7, 0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96,
+       0xF1, 0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C,
+       0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE, 0x03,
+       0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11, 0xF8, 0x63,
+       0x9A, 0x39, 0xFE, 0x32, 0x36, 0x75, 0x18, 0x35,
+       0xA5, 0xE5, 0xE4, 0x43, 0x17, 0xC1, 0xC2, 0xEE,
+       0xFD, 0x4E, 0xA5, 0xBF, 0xD1, 0x60, 0x43, 0xF4,
+       0x3C, 0xB4, 0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D,
+       0x03, 0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53,
+       0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C, 0x16,
+       0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55, 0xB5, 0x1B,
+       0x22, 0xCB, 0xF4, 0x4C, 0xD0, 0x12, 0xAE, 0xE0,
+       0xB2, 0x79, 0x8E, 0x62, 0x84, 0x23, 0x42, 0x8E,
+       0xFC, 0xD5, 0xA4, 0x0C, 0xAE, 0xF6, 0xBF, 0x50,
+       0xD8, 0xEA, 0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9,
+       0xFD, 0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34,
+       0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF, 0xC9,
+       0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E, 0x36, 0x6B,
+       0xC4, 0x4D, 0x00, 0x17, 0x6A, 0xF7, 0x1C, 0x15,
+       0xE4, 0x8C, 0x86, 0xD3, 0x7E, 0x01, 0x37, 0x23,
+       0xCA, 0xAC, 0x72, 0x23, 0xAB, 0x3B, 0xF4, 0xD5,
+       0x4F, 0x18, 0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F,
+       0xE4, 0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38,
+       0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9, 0xEF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/*
+ * RFC 5114, 2.1.
+ * Group 22 - 1024-bit MODP Group with 160-bit Prime Order Subgroup
+ */
+static const u8 dh_group22_generator[] = {
+       0xA4, 0xD1, 0xCB, 0xD5, 0xC3, 0xFD, 0x34, 0x12,
+       0x67, 0x65, 0xA4, 0x42, 0xEF, 0xB9, 0x99, 0x05,
+       0xF8, 0x10, 0x4D, 0xD2, 0x58, 0xAC, 0x50, 0x7F,
+       0xD6, 0x40, 0x6C, 0xFF, 0x14, 0x26, 0x6D, 0x31,
+       0x26, 0x6F, 0xEA, 0x1E, 0x5C, 0x41, 0x56, 0x4B,
+       0x77, 0x7E, 0x69, 0x0F, 0x55, 0x04, 0xF2, 0x13,
+       0x16, 0x02, 0x17, 0xB4, 0xB0, 0x1B, 0x88, 0x6A,
+       0x5E, 0x91, 0x54, 0x7F, 0x9E, 0x27, 0x49, 0xF4,
+       0xD7, 0xFB, 0xD7, 0xD3, 0xB9, 0xA9, 0x2E, 0xE1,
+       0x90, 0x9D, 0x0D, 0x22, 0x63, 0xF8, 0x0A, 0x76,
+       0xA6, 0xA2, 0x4C, 0x08, 0x7A, 0x09, 0x1F, 0x53,
+       0x1D, 0xBF, 0x0A, 0x01, 0x69, 0xB6, 0xA2, 0x8A,
+       0xD6, 0x62, 0xA4, 0xD1, 0x8E, 0x73, 0xAF, 0xA3,
+       0x2D, 0x77, 0x9D, 0x59, 0x18, 0xD0, 0x8B, 0xC8,
+       0x85, 0x8F, 0x4D, 0xCE, 0xF9, 0x7C, 0x2A, 0x24,
+       0x85, 0x5E, 0x6E, 0xEB, 0x22, 0xB3, 0xB2, 0xE5
+};
+static const u8 dh_group22_prime[] = {
+       0xB1, 0x0B, 0x8F, 0x96, 0xA0, 0x80, 0xE0, 0x1D,
+       0xDE, 0x92, 0xDE, 0x5E, 0xAE, 0x5D, 0x54, 0xEC,
+       0x52, 0xC9, 0x9F, 0xBC, 0xFB, 0x06, 0xA3, 0xC6,
+       0x9A, 0x6A, 0x9D, 0xCA, 0x52, 0xD2, 0x3B, 0x61,
+       0x60, 0x73, 0xE2, 0x86, 0x75, 0xA2, 0x3D, 0x18,
+       0x98, 0x38, 0xEF, 0x1E, 0x2E, 0xE6, 0x52, 0xC0,
+       0x13, 0xEC, 0xB4, 0xAE, 0xA9, 0x06, 0x11, 0x23,
+       0x24, 0x97, 0x5C, 0x3C, 0xD4, 0x9B, 0x83, 0xBF,
+       0xAC, 0xCB, 0xDD, 0x7D, 0x90, 0xC4, 0xBD, 0x70,
+       0x98, 0x48, 0x8E, 0x9C, 0x21, 0x9A, 0x73, 0x72,
+       0x4E, 0xFF, 0xD6, 0xFA, 0xE5, 0x64, 0x47, 0x38,
+       0xFA, 0xA3, 0x1A, 0x4F, 0xF5, 0x5B, 0xCC, 0xC0,
+       0xA1, 0x51, 0xAF, 0x5F, 0x0D, 0xC8, 0xB4, 0xBD,
+       0x45, 0xBF, 0x37, 0xDF, 0x36, 0x5C, 0x1A, 0x65,
+       0xE6, 0x8C, 0xFD, 0xA7, 0x6D, 0x4D, 0xA7, 0x08,
+       0xDF, 0x1F, 0xB2, 0xBC, 0x2E, 0x4A, 0x43, 0x71
+};
+static const u8 dh_group22_order[] = {
+       0xF5, 0x18, 0xAA, 0x87, 0x81, 0xA8, 0xDF, 0x27,
+       0x8A, 0xBA, 0x4E, 0x7D, 0x64, 0xB7, 0xCB, 0x9D,
+       0x49, 0x46, 0x23, 0x53
+};
+
+/*
+ * RFC 5114, 2.2.
+ * Group 23 - 2048-bit MODP Group with 224-bit Prime Order Subgroup
+ */
+static const u8 dh_group23_generator[] = {
+       0xAC, 0x40, 0x32, 0xEF, 0x4F, 0x2D, 0x9A, 0xE3,
+       0x9D, 0xF3, 0x0B, 0x5C, 0x8F, 0xFD, 0xAC, 0x50,
+       0x6C, 0xDE, 0xBE, 0x7B, 0x89, 0x99, 0x8C, 0xAF,
+       0x74, 0x86, 0x6A, 0x08, 0xCF, 0xE4, 0xFF, 0xE3,
+       0xA6, 0x82, 0x4A, 0x4E, 0x10, 0xB9, 0xA6, 0xF0,
+       0xDD, 0x92, 0x1F, 0x01, 0xA7, 0x0C, 0x4A, 0xFA,
+       0xAB, 0x73, 0x9D, 0x77, 0x00, 0xC2, 0x9F, 0x52,
+       0xC5, 0x7D, 0xB1, 0x7C, 0x62, 0x0A, 0x86, 0x52,
+       0xBE, 0x5E, 0x90, 0x01, 0xA8, 0xD6, 0x6A, 0xD7,
+       0xC1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4A,
+       0xF4, 0xD0, 0x27, 0x27, 0x5A, 0xC1, 0x34, 0x8B,
+       0xB8, 0xA7, 0x62, 0xD0, 0x52, 0x1B, 0xC9, 0x8A,
+       0xE2, 0x47, 0x15, 0x04, 0x22, 0xEA, 0x1E, 0xD4,
+       0x09, 0x93, 0x9D, 0x54, 0xDA, 0x74, 0x60, 0xCD,
+       0xB5, 0xF6, 0xC6, 0xB2, 0x50, 0x71, 0x7C, 0xBE,
+       0xF1, 0x80, 0xEB, 0x34, 0x11, 0x8E, 0x98, 0xD1,
+       0x19, 0x52, 0x9A, 0x45, 0xD6, 0xF8, 0x34, 0x56,
+       0x6E, 0x30, 0x25, 0xE3, 0x16, 0xA3, 0x30, 0xEF,
+       0xBB, 0x77, 0xA8, 0x6F, 0x0C, 0x1A, 0xB1, 0x5B,
+       0x05, 0x1A, 0xE3, 0xD4, 0x28, 0xC8, 0xF8, 0xAC,
+       0xB7, 0x0A, 0x81, 0x37, 0x15, 0x0B, 0x8E, 0xEB,
+       0x10, 0xE1, 0x83, 0xED, 0xD1, 0x99, 0x63, 0xDD,
+       0xD9, 0xE2, 0x63, 0xE4, 0x77, 0x05, 0x89, 0xEF,
+       0x6A, 0xA2, 0x1E, 0x7F, 0x5F, 0x2F, 0xF3, 0x81,
+       0xB5, 0x39, 0xCC, 0xE3, 0x40, 0x9D, 0x13, 0xCD,
+       0x56, 0x6A, 0xFB, 0xB4, 0x8D, 0x6C, 0x01, 0x91,
+       0x81, 0xE1, 0xBC, 0xFE, 0x94, 0xB3, 0x02, 0x69,
+       0xED, 0xFE, 0x72, 0xFE, 0x9B, 0x6A, 0xA4, 0xBD,
+       0x7B, 0x5A, 0x0F, 0x1C, 0x71, 0xCF, 0xFF, 0x4C,
+       0x19, 0xC4, 0x18, 0xE1, 0xF6, 0xEC, 0x01, 0x79,
+       0x81, 0xBC, 0x08, 0x7F, 0x2A, 0x70, 0x65, 0xB3,
+       0x84, 0xB8, 0x90, 0xD3, 0x19, 0x1F, 0x2B, 0xFA
+};
+static const u8 dh_group23_prime[] = {
+       0xAD, 0x10, 0x7E, 0x1E, 0x91, 0x23, 0xA9, 0xD0,
+       0xD6, 0x60, 0xFA, 0xA7, 0x95, 0x59, 0xC5, 0x1F,
+       0xA2, 0x0D, 0x64, 0xE5, 0x68, 0x3B, 0x9F, 0xD1,
+       0xB5, 0x4B, 0x15, 0x97, 0xB6, 0x1D, 0x0A, 0x75,
+       0xE6, 0xFA, 0x14, 0x1D, 0xF9, 0x5A, 0x56, 0xDB,
+       0xAF, 0x9A, 0x3C, 0x40, 0x7B, 0xA1, 0xDF, 0x15,
+       0xEB, 0x3D, 0x68, 0x8A, 0x30, 0x9C, 0x18, 0x0E,
+       0x1D, 0xE6, 0xB8, 0x5A, 0x12, 0x74, 0xA0, 0xA6,
+       0x6D, 0x3F, 0x81, 0x52, 0xAD, 0x6A, 0xC2, 0x12,
+       0x90, 0x37, 0xC9, 0xED, 0xEF, 0xDA, 0x4D, 0xF8,
+       0xD9, 0x1E, 0x8F, 0xEF, 0x55, 0xB7, 0x39, 0x4B,
+       0x7A, 0xD5, 0xB7, 0xD0, 0xB6, 0xC1, 0x22, 0x07,
+       0xC9, 0xF9, 0x8D, 0x11, 0xED, 0x34, 0xDB, 0xF6,
+       0xC6, 0xBA, 0x0B, 0x2C, 0x8B, 0xBC, 0x27, 0xBE,
+       0x6A, 0x00, 0xE0, 0xA0, 0xB9, 0xC4, 0x97, 0x08,
+       0xB3, 0xBF, 0x8A, 0x31, 0x70, 0x91, 0x88, 0x36,
+       0x81, 0x28, 0x61, 0x30, 0xBC, 0x89, 0x85, 0xDB,
+       0x16, 0x02, 0xE7, 0x14, 0x41, 0x5D, 0x93, 0x30,
+       0x27, 0x82, 0x73, 0xC7, 0xDE, 0x31, 0xEF, 0xDC,
+       0x73, 0x10, 0xF7, 0x12, 0x1F, 0xD5, 0xA0, 0x74,
+       0x15, 0x98, 0x7D, 0x9A, 0xDC, 0x0A, 0x48, 0x6D,
+       0xCD, 0xF9, 0x3A, 0xCC, 0x44, 0x32, 0x83, 0x87,
+       0x31, 0x5D, 0x75, 0xE1, 0x98, 0xC6, 0x41, 0xA4,
+       0x80, 0xCD, 0x86, 0xA1, 0xB9, 0xE5, 0x87, 0xE8,
+       0xBE, 0x60, 0xE6, 0x9C, 0xC9, 0x28, 0xB2, 0xB9,
+       0xC5, 0x21, 0x72, 0xE4, 0x13, 0x04, 0x2E, 0x9B,
+       0x23, 0xF1, 0x0B, 0x0E, 0x16, 0xE7, 0x97, 0x63,
+       0xC9, 0xB5, 0x3D, 0xCF, 0x4B, 0xA8, 0x0A, 0x29,
+       0xE3, 0xFB, 0x73, 0xC1, 0x6B, 0x8E, 0x75, 0xB9,
+       0x7E, 0xF3, 0x63, 0xE2, 0xFF, 0xA3, 0x1F, 0x71,
+       0xCF, 0x9D, 0xE5, 0x38, 0x4E, 0x71, 0xB8, 0x1C,
+       0x0A, 0xC4, 0xDF, 0xFE, 0x0C, 0x10, 0xE6, 0x4F
+};
+static const u8 dh_group23_order[] = {
+       0x80, 0x1C, 0x0D, 0x34, 0xC5, 0x8D, 0x93, 0xFE,
+       0x99, 0x71, 0x77, 0x10, 0x1F, 0x80, 0x53, 0x5A,
+       0x47, 0x38, 0xCE, 0xBC, 0xBF, 0x38, 0x9A, 0x99,
+       0xB3, 0x63, 0x71, 0xEB
+};
+
+/*
+ * RFC 5114, 2.3.
+ * Group 24 - 2048-bit MODP Group with 256-bit Prime Order Subgroup
+ */
+static const u8 dh_group24_generator[] = {
+       0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B,
+       0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48,
+       0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54,
+       0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25,
+       0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F,
+       0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55,
+       0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1,
+       0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62,
+       0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18,
+       0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65,
+       0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2,
+       0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B,
+       0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62,
+       0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38,
+       0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83,
+       0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93,
+       0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1,
+       0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55,
+       0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80,
+       0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A,
+       0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14,
+       0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9,
+       0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99,
+       0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15,
+       0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37,
+       0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52,
+       0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6,
+       0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3,
+       0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8,
+       0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51,
+       0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82,
+       0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59
+};
+static const u8 dh_group24_prime[] = {
+       0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C,
+       0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99,
+       0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2,
+       0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00,
+       0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4,
+       0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30,
+       0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA,
+       0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C,
+       0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD,
+       0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED,
+       0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0,
+       0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B,
+       0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88,
+       0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8,
+       0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C,
+       0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76,
+       0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90,
+       0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E,
+       0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB,
+       0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E,
+       0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9,
+       0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25,
+       0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6,
+       0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26,
+       0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56,
+       0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21,
+       0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3,
+       0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03,
+       0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12,
+       0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F,
+       0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA,
+       0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97
+};
+static const u8 dh_group24_order[] = {
+       0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97,
+       0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2,
+       0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B,
+       0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3
+};
 
 #endif /* ALL_DH_GROUPS */
 
 
-#define DH_GROUP(id) \
+#define DH_GROUP(id,safe) \
 { id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
-dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
+dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
                
 
 static struct dh_group dh_groups[] = {
-       DH_GROUP(5),
+       DH_GROUP(5, 1),
 #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)
+       DH_GROUP(1, 1),
+       DH_GROUP(2, 1),
+       DH_GROUP(14, 1),
+       DH_GROUP(15, 1),
+       DH_GROUP(16, 1),
+       DH_GROUP(17, 1),
+       DH_GROUP(18, 1),
+       DH_GROUP(22, 0),
+       DH_GROUP(23, 0),
+       DH_GROUP(24, 0)
 #endif /* ALL_DH_GROUPS */
 };
 
index 5c61539..d0e74b9 100644 (file)
@@ -2,14 +2,8 @@
  * Diffie-Hellman groups
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DH_GROUPS_H
@@ -21,6 +15,9 @@ struct dh_group {
        size_t generator_len;
        const u8 *prime;
        size_t prime_len;
+       const u8 *order;
+       size_t order_len;
+       unsigned int safe_prime:1;
 };
 
 const struct dh_group * dh_groups_get(int id);
index 17d3116..dca93a3 100644 (file)
@@ -2,14 +2,8 @@
  * FIPS 186-2 PRF for Microsoft CryptoAPI
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f742e98..947e6f6 100644 (file)
@@ -2,14 +2,8 @@
  * FIPS 186-2 PRF for libgcrypt
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 1e0c453..a4bf50a 100644 (file)
@@ -2,14 +2,8 @@
  * FIPS 186-2 PRF for internal crypto implementation
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f941983..2c962f4 100644 (file)
@@ -2,14 +2,8 @@
  * FIPS 186-2 PRF for NSS
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index d0af983..d69ecea 100644 (file)
@@ -2,14 +2,8 @@
  * FIPS 186-2 PRF for libcrypto
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -37,13 +31,14 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
        u8 *xpos = x;
        u32 carry;
 
-       if (seed_len > sizeof(xkey))
+       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);
-       os_memset(xkey + seed_len, 0, 64 - seed_len);
        t[0] = 0x67452301;
        t[1] = 0xEFCDAB89;
        t[2] = 0x98BADCFE;
index d9f499f..cd5e6ca 100644 (file)
@@ -2,14 +2,8 @@
  * MD4 hash implementation
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 137ad91..f0a2a5d 100644 (file)
@@ -2,14 +2,8 @@
  * MD5 hash implementation and interface functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -182,8 +176,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
     byteReverse(ctx->in, 14);
 
     /* Append length in bits and transform */
-    ((u32 *) ctx->in)[14] = ctx->bits[0];
-    ((u32 *) ctx->in)[15] = ctx->bits[1];
+    ((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);
diff --git a/src/crypto/md5-non-fips.c b/src/crypto/md5-non-fips.c
deleted file mode 100644 (file)
index 6f29201..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * MD5 hash implementation and interface functions (non-FIPS allowed cases)
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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);
-}
index 7f14e9b..db2b8cc 100644 (file)
@@ -2,14 +2,8 @@
  * MD5 hash implementation and interface functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 8952590..33f8426 100644 (file)
@@ -2,14 +2,8 @@
  * MD5 hash implementation and interface functions
  * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MD5_H
@@ -21,15 +15,5 @@ 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 */
index b7f6596..7dfc100 100644 (file)
@@ -2,14 +2,8 @@
  * MD5 internal definitions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MD5_I_H
index cf0c60e..a7f9c6a 100644 (file)
@@ -2,14 +2,8 @@
  * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
  * Copyright (c) 2006-2007 <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index d5054d6..62137d9 100644 (file)
@@ -2,14 +2,8 @@
  * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
  * Copyright (c) 2006-2007 <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MILENAGE_H
index c439ae9..b2bbab2 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -179,8 +173,9 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
        u8 challenge[8];
        u8 password_hash[16];
 
-       challenge_hash(peer_challenge, auth_challenge, username, username_len,
-                      challenge);
+       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);
@@ -266,8 +261,9 @@ int generate_authenticator_response_pwhash(
        if (sha1_vector(3, addr1, len1, response))
                return -1;
 
-       challenge_hash(peer_challenge, auth_challenge, username, username_len,
-                      challenge);
+       if (challenge_hash(peer_challenge, auth_challenge, username,
+                          username_len, challenge))
+               return -1;
        return sha1_vector(3, addr2, len2, response);
 }
 
index 298dbcf..bd9bfee 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MS_FUNCS_H
index a54e197..053740e 100644 (file)
@@ -2,14 +2,8 @@
  * Random number generator
  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -35,6 +29,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "crypto/crypto.h"
 #include "sha1.h"
 #include "random.h"
 
@@ -134,8 +129,6 @@ void random_add_randomness(const void *buf, size_t len)
        static unsigned int count = 0;
 
        count++;
-       wpa_printf(MSG_MSGDUMP, "Add randomness: count=%u entropy=%u",
-                  count, entropy);
        if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
                /*
                 * No need to add more entropy at this point, so save CPU and
@@ -143,6 +136,8 @@ void random_add_randomness(const void *buf, size_t len)
                 */
                return;
        }
+       wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+                  count, entropy);
 
        os_get_time(&t);
        wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
@@ -183,6 +178,27 @@ int random_get_bytes(void *buf, size_t len)
                        *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)
index 1048bb4..d13e1c4 100644 (file)
@@ -2,14 +2,8 @@
  * Random number generator
  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RANDOM_H
index 5ab1be1..98ae269 100644 (file)
@@ -2,14 +2,8 @@
  * RC4 stream cipher
  * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 3f05ca1..10bf153 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1 hash implementation and interface functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 9dac977..8effe2f 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -17,7 +11,7 @@
 #include "common.h"
 #include "sha1.h"
 
-static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
+static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid,
                         size_t ssid_len, int iterations, unsigned int count,
                         u8 *digest)
 {
@@ -28,7 +22,7 @@ static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
        size_t len[2];
        size_t passphrase_len = os_strlen(passphrase);
 
-       addr[0] = (u8 *) ssid;
+       addr[0] = ssid;
        len[0] = ssid_len;
        addr[1] = count_buf;
        len[1] = 4;
@@ -75,7 +69,7 @@ static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
  * 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 pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
                int iterations, u8 *buf, size_t buflen)
 {
        unsigned int count = 0;
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
new file mode 100644 (file)
index 0000000..90b9e74
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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;
+}
index f98fd65..0effd9b 100644 (file)
@@ -2,14 +2,8 @@
  * TLS PRF (SHA1 + MD5)
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -77,19 +71,16 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
                S2--;
        }
 
-       hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
-                                      A_MD5);
+       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_non_fips_allow(S1, L_S1, 3, MD5_addr,
-                                                      MD5_len, P_MD5);
+                       hmac_md5_vector(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);
+                       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,
index 4a80e96..a529494 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1 T-PRF for EAP-FAST
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index fe00bdb..d48c77d 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1 hash implementation and interface functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -108,56 +102,3 @@ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 {
        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;
-}
index f0c1a5f..933cd81 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1 hash implementation and interface functions
  * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SHA1_H
@@ -28,6 +22,6 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
 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 char *ssid, size_t ssid_len,
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
                int iterations, u8 *buf, size_t buflen);
 #endif /* SHA1_H */
index ec2f82f..344387e 100644 (file)
@@ -2,14 +2,8 @@
  * SHA1 internal definitions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SHA1_I_H
index ef5751d..35299b0 100644 (file)
@@ -2,14 +2,8 @@
  * SHA-256 hash implementation and interface functions
  * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
new file mode 100644 (file)
index 0000000..9a11208
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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)
+{
+       sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+}
+
+
+/**
+ * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+                    const u8 *data, size_t data_len, u8 *buf,
+                    size_t buf_len_bits)
+{
+       u16 counter = 1;
+       size_t pos, plen;
+       u8 hash[SHA256_MAC_LEN];
+       const u8 *addr[4];
+       size_t len[4];
+       u8 counter_le[2], length_le[2];
+       size_t buf_len = (buf_len_bits + 7) / 8;
+
+       addr[0] = counter_le;
+       len[0] = 2;
+       addr[1] = (u8 *) label;
+       len[1] = os_strlen(label);
+       addr[2] = data;
+       len[2] = data_len;
+       addr[3] = length_le;
+       len[3] = sizeof(length_le);
+
+       WPA_PUT_LE16(length_le, buf_len_bits);
+       pos = 0;
+       while (pos < buf_len) {
+               plen = buf_len - pos;
+               WPA_PUT_LE16(counter_le, counter);
+               if (plen >= 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);
+                       pos += plen;
+                       break;
+               }
+               counter++;
+       }
+
+       /*
+        * Mask out unused bits in the last octet if it does not use all the
+        * bits.
+        */
+       if (buf_len_bits % 8) {
+               u8 mask = 0xff << (8 - buf_len_bits % 8);
+               buf[pos - 1] &= mask;
+       }
+}
index 6763c96..0528dad 100644 (file)
@@ -2,14 +2,8 @@
  * TLS PRF P_SHA256
  * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 7f320f9..b55e976 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
  * @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
  */
-void 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_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];
@@ -41,12 +36,13 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
                 * Fixed limit on the number of fragments to avoid having to
                 * allocate memory (which could fail).
                 */
-               return;
+               return -1;
        }
 
         /* if key is longer than 64 bytes reset it to key = SHA256(key) */
         if (key_len > 64) {
-               sha256_vector(1, &key, &key_len, tk);
+               if (sha256_vector(1, &key, &key_len, tk) < 0)
+                       return -1;
                key = tk;
                key_len = 32;
         }
@@ -74,7 +70,8 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
                _addr[i + 1] = addr[i];
                _len[i + 1] = len[i];
        }
-       sha256_vector(1 + num_elem, _addr, _len, mac);
+       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);
@@ -87,7 +84,7 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
        _len[0] = 64;
        _addr[1] = mac;
        _len[1] = SHA256_MAC_LEN;
-       sha256_vector(2, _addr, _len, mac);
+       return sha256_vector(2, _addr, _len, mac);
 }
 
 
@@ -97,61 +94,11 @@ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
  * @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.
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
  */
-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)
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+               size_t data_len, u8 *mac)
 {
-       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++;
-       }
+       return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
 }
index b1ce6af..7596a52 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef 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);
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+                      const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+               size_t data_len, u8 *mac);
 void sha256_prf(const u8 *key, size_t key_len, const char *label,
              const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+                    const u8 *data, size_t data_len, u8 *buf,
+                    size_t buf_len_bits);
 void tls_prf_sha256(const u8 *secret, size_t secret_len,
                    const char *label, const u8 *seed, size_t seed_len,
                    u8 *out, size_t outlen);
index 20ae488..a502d2b 100644 (file)
@@ -2,14 +2,8 @@
  * SHA-256 internal definitions
  * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SHA256_I_H
index d9d88cb..2fdaa02 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * SSL/TLS interface definition
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLS_H
@@ -27,8 +21,10 @@ struct tls_keys {
 };
 
 enum tls_event {
+       TLS_CERT_CHAIN_SUCCESS,
        TLS_CERT_CHAIN_FAILURE,
-       TLS_PEER_CERTIFICATE
+       TLS_PEER_CERTIFICATE,
+       TLS_ALERT
 };
 
 /*
@@ -63,6 +59,12 @@ union tls_event_data {
                const u8 *hash;
                size_t hash_len;
        } peer_cert;
+
+       struct {
+               int is_local;
+               const char *type;
+               const char *description;
+       } alert;
 };
 
 struct tls_config {
@@ -79,6 +81,9 @@ struct tls_config {
 
 #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 #define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+#define TLS_CONN_REQUEST_OCSP BIT(3)
+#define TLS_CONN_REQUIRE_OCSP BIT(4)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -114,6 +119,8 @@ struct tls_config {
  * @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_*)
+ * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
+ *     or %NULL if OCSP is not enabled
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
  * and tls_global_set_params().
@@ -150,6 +157,7 @@ struct tls_connection_params {
        const char *ca_cert_id;
 
        unsigned int flags;
+       const char *ocsp_stapling_response;
 };
 
 
index afa5268..a5d72f4 100644 (file)
@@ -2,14 +2,8 @@
  * SSL/TLS interface functions for GnuTLS
  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f5e31d9..91f0690 100644 (file)
@@ -2,14 +2,8 @@
  * TLS interface functions and an internal TLS implementation
  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
index 927edf5..1a1092a 100644 (file)
@@ -2,14 +2,8 @@
  * SSL/TLS interface functions for no TLS case
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 09a1e73..c53c192 100644 (file)
@@ -2,14 +2,8 @@
  * SSL/TLS interface functions for NSS
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 8374096..28b1313 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #define OPENSSL_d2i_TYPE unsigned char **
 #endif
 
+#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
+#define OPENSSL_SUPPORTS_CTX_APP_DATA
+#endif
+
 #ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
 #ifdef SSL_OP_NO_TICKET
 /*
 #endif
 #endif
 
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
 static int tls_openssl_ref_count = 0;
 
-struct tls_global {
+struct tls_context {
        void (*event_cb)(void *ctx, enum tls_event ev,
                         union tls_event_data *data);
        void *cb_ctx;
        int cert_in_cb;
+       char *ocsp_stapling_response;
 };
 
-static struct tls_global *tls_global = NULL;
+static struct tls_context *tls_global = NULL;
 
 
 struct tls_connection {
+       struct tls_context *context;
        SSL *ssl;
        BIO *ssl_in, *ssl_out;
 #ifndef OPENSSL_NO_ENGINE
@@ -89,9 +96,26 @@ struct tls_connection {
        u8 srv_cert_hash[32];
 
        unsigned int flags;
+
+       X509 *peer_cert;
+       X509 *peer_issuer;
 };
 
 
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+       struct tls_context *context = os_zalloc(sizeof(*context));
+       if (context == NULL)
+               return NULL;
+       if (conf) {
+               context->event_cb = conf->event_cb;
+               context->cb_ctx = conf->cb_ctx;
+               context->cert_in_cb = conf->cert_in_cb;
+       }
+       return context;
+}
+
+
 #ifdef CONFIG_NO_STDOUT_DEBUG
 
 static void _tls_show_errors(void)
@@ -517,6 +541,7 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
                wpa_printf(MSG_DEBUG, "SSL: %s:%s",
                           str, SSL_state_string_long(ssl));
        } else if (where & SSL_CB_ALERT) {
+               struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
                wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
                           where & SSL_CB_READ ?
                           "read (remote end reported an error)" :
@@ -524,13 +549,20 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
                           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 (conn->context->event_cb != NULL) {
+                       union tls_event_data ev;
+                       struct tls_context *context = conn->context;
+                       os_memset(&ev, 0, sizeof(ev));
+                       ev.alert.is_local = !(where & SSL_CB_READ);
+                       ev.alert.type = SSL_alert_type_string_long(ret);
+                       ev.alert.description = SSL_alert_desc_string_long(ret);
+                       context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
+               }
        } else if (where & SSL_CB_EXIT && ret <= 0) {
                wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
                           str, ret == 0 ? "failed" : "error",
@@ -687,17 +719,12 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
 void * tls_init(const struct tls_config *conf)
 {
        SSL_CTX *ssl;
+       struct tls_context *context;
 
        if (tls_openssl_ref_count == 0) {
-               tls_global = os_zalloc(sizeof(*tls_global));
-               if (tls_global == NULL)
+               tls_global = context = tls_context_new(conf);
+               if (context == 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) {
@@ -706,6 +733,8 @@ void * tls_init(const struct tls_config *conf)
                                           "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");
@@ -714,6 +743,8 @@ void * tls_init(const struct tls_config *conf)
                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 */
@@ -739,14 +770,33 @@ void * tls_init(const struct tls_config *conf)
 #endif /* OPENSSL_NO_RC2 */
                PKCS12_PBE_add();
 #endif  /* PKCS12_FUNCS */
+       } else {
+               context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+               /* Newer OpenSSL can store app-data per-SSL */
+               context = tls_context_new(conf);
+               if (context == NULL)
+                       return NULL;
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
        }
        tls_openssl_ref_count++;
 
        ssl = SSL_CTX_new(TLSv1_method());
-       if (ssl == NULL)
+       if (ssl == NULL) {
+               tls_openssl_ref_count--;
+               if (tls_openssl_ref_count == 0) {
+                       os_free(tls_global);
+                       tls_global = NULL;
+               } else if (context != tls_global) {
+                       os_free(context);
+               }
                return NULL;
+       }
 
        SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+       SSL_CTX_set_app_data(ssl, context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 
 #ifndef OPENSSL_NO_ENGINE
        if (conf &&
@@ -772,6 +822,11 @@ void * tls_init(const struct tls_config *conf)
 void tls_deinit(void *ssl_ctx)
 {
        SSL_CTX *ssl = ssl_ctx;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+       struct tls_context *context = SSL_CTX_get_app_data(ssl);
+       if (context != tls_global)
+               os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
        SSL_CTX_free(ssl);
 
        tls_openssl_ref_count--;
@@ -783,6 +838,8 @@ void tls_deinit(void *ssl_ctx)
                ERR_remove_state(0);
                ERR_free_strings();
                EVP_cleanup();
+               os_free(tls_global->ocsp_stapling_response);
+               tls_global->ocsp_stapling_response = NULL;
                os_free(tls_global);
                tls_global = NULL;
        }
@@ -908,6 +965,10 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
        SSL_CTX *ssl = ssl_ctx;
        struct tls_connection *conn;
        long options;
+       struct tls_context *context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+       context = SSL_CTX_get_app_data(ssl);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 
        conn = os_zalloc(sizeof(*conn));
        if (conn == NULL)
@@ -920,6 +981,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
                return NULL;
        }
 
+       conn->context = context;
        SSL_set_app_data(conn->ssl, conn);
        options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
                SSL_OP_SINGLE_DH_USE;
@@ -1115,8 +1177,9 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
 {
        union tls_event_data ev;
        struct wpabuf *cert = NULL;
+       struct tls_context *context = conn->context;
 
-       if (tls_global->event_cb == NULL)
+       if (context->event_cb == NULL)
                return;
 
        cert = get_x509_cert(err_cert);
@@ -1127,7 +1190,7 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
        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);
+       context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
        wpabuf_free(cert);
 }
 
@@ -1138,15 +1201,16 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
 {
        struct wpabuf *cert = NULL;
        union tls_event_data ev;
+       struct tls_context *context = conn->context;
 #ifdef CONFIG_SHA256
        u8 hash[32];
 #endif /* CONFIG_SHA256 */
 
-       if (tls_global->event_cb == NULL)
+       if (context->event_cb == NULL)
                return;
 
        os_memset(&ev, 0, sizeof(ev));
-       if (conn->cert_probe || tls_global->cert_in_cb) {
+       if (conn->cert_probe || context->cert_in_cb) {
                cert = get_x509_cert(err_cert);
                ev.peer_cert.cert = cert;
        }
@@ -1164,7 +1228,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
 #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);
+       context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
        wpabuf_free(cert);
 }
 
@@ -1176,6 +1240,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        int err, depth;
        SSL *ssl;
        struct tls_connection *conn;
+       struct tls_context *context;
        char *match, *altmatch;
        const char *err_str;
 
@@ -1189,6 +1254,13 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        conn = SSL_get_app_data(ssl);
        if (conn == NULL)
                return 0;
+
+       if (depth == 0)
+               conn->peer_cert = err_cert;
+       else if (depth == 1)
+               conn->peer_issuer = err_cert;
+
+       context = conn->context;
        match = conn->subject_match;
        altmatch = conn->altsubject_match;
 
@@ -1271,6 +1343,10 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_SERVER_CHAIN_PROBE);
        }
 
+       if (preverify_ok && context->event_cb != NULL)
+               context->event_cb(context->cb_ctx,
+                                 TLS_CERT_CHAIN_SUCCESS, NULL);
+
        return preverify_ok;
 }
 
@@ -1915,6 +1991,8 @@ static int tls_connection_engine_ca_cert(void *_ssl_ctx,
        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 */
@@ -2078,7 +2156,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
        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");
@@ -2124,7 +2202,7 @@ static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
        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");
@@ -2286,6 +2364,11 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
                            struct tls_keys *keys)
 {
+#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)
@@ -2303,6 +2386,7 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
        keys->server_random_len = SSL3_RANDOM_SIZE;
 
        return 0;
+#endif /* CONFIG_FIPS */
 }
 
 
@@ -2310,6 +2394,19 @@ 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;
 }
 
@@ -2677,11 +2774,187 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
 }
 
 
+#ifdef HAVE_OCSP
+
+static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       extern int wpa_debug_level;
+       BIO *out;
+       size_t rlen;
+       char *txt;
+       int res;
+
+       if (wpa_debug_level > MSG_DEBUG)
+               return;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return;
+
+       OCSP_RESPONSE_print(out, rsp, 0);
+       rlen = BIO_ctrl_pending(out);
+       txt = os_malloc(rlen + 1);
+       if (!txt) {
+               BIO_free(out);
+               return;
+       }
+
+       res = BIO_read(out, txt, rlen);
+       if (res > 0) {
+               txt[res] = '\0';
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
+       }
+       os_free(txt);
+       BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+       struct tls_connection *conn = arg;
+       const unsigned char *p;
+       int len, status, reason;
+       OCSP_RESPONSE *rsp;
+       OCSP_BASICRESP *basic;
+       OCSP_CERTID *id;
+       ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+
+       len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+       if (!p) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+               return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+       rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+       if (!rsp) {
+               wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+               return 0;
+       }
+
+       ocsp_debug_print_resp(rsp);
+
+       status = OCSP_response_status(rsp);
+       if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+               wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+                          status, OCSP_response_status_str(status));
+               return 0;
+       }
+
+       basic = OCSP_response_get1_basic(rsp);
+       if (!basic) {
+               wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+               return 0;
+       }
+
+       status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx),
+                                  0);
+       if (status <= 0) {
+               tls_show_errors(MSG_INFO, __func__,
+                               "OpenSSL: OCSP response failed verification");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
+
+       if (!conn->peer_cert || !conn->peer_issuer) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate or issue certificate not available for OCSP status check");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+       if (!id) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+                                  &this_update, &next_update)) {
+               wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+                          (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
+                          " (OCSP not required)");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+       }
+
+       if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+               tls_show_errors(MSG_INFO, __func__,
+                               "OpenSSL: OCSP status times invalid");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       OCSP_BASICRESP_free(basic);
+       OCSP_RESPONSE_free(rsp);
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+                  OCSP_cert_status_str(status));
+
+       if (status == V_OCSP_CERTSTATUS_GOOD)
+               return 1;
+       if (status == V_OCSP_CERTSTATUS_REVOKED)
+               return 0;
+       if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
+               return 0;
+       }
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+       return 1;
+}
+
+
+static int ocsp_status_cb(SSL *s, void *arg)
+{
+       char *tmp;
+       char *resp;
+       size_t len;
+
+       if (tls_global->ocsp_stapling_response == NULL) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
+               return SSL_TLSEXT_ERR_OK;
+       }
+
+       resp = os_readfile(tls_global->ocsp_stapling_response, &len);
+       if (resp == NULL) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
+               /* TODO: Build OCSPResponse with responseStatus = internalError
+                */
+               return SSL_TLSEXT_ERR_OK;
+       }
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
+       tmp = OPENSSL_malloc(len);
+       if (tmp == NULL) {
+               os_free(resp);
+               return SSL_TLSEXT_ERR_ALERT_FATAL;
+       }
+
+       os_memcpy(tmp, resp, len);
+       os_free(resp);
+       SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
+
+       return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* HAVE_OCSP */
+
+
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                              const struct tls_connection_params *params)
 {
        int ret;
        unsigned long err;
+       SSL_CTX *ssl_ctx = tls_ctx;
 
        if (conn == NULL)
                return -1;
@@ -2742,6 +3015,23 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
+#ifdef SSL_OP_NO_TICKET
+       if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+               SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
+       else
+               SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
+#endif /*  SSL_OP_NO_TICKET */
+
+#ifdef HAVE_OCSP
+       if (params->flags & TLS_CONN_REQUEST_OCSP) {
+               SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
+               SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
+               SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
+       }
+#endif /* HAVE_OCSP */
+
        conn->flags = params->flags;
 
        tls_get_errors(tls_ctx);
@@ -2777,6 +3067,26 @@ int tls_global_set_params(void *tls_ctx,
                return -1;
        }
 
+#ifdef SSL_OP_NO_TICKET
+       if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+               SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+#ifdef SSL_CTX_clear_options
+       else
+               SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
+#endif /*  SSL_OP_NO_TICKET */
+
+#ifdef HAVE_OCSP
+       SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
+       SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
+       os_free(tls_global->ocsp_stapling_response);
+       if (params->ocsp_stapling_response)
+               tls_global->ocsp_stapling_response =
+                       os_strdup(params->ocsp_stapling_response);
+       else
+               tls_global->ocsp_stapling_response = NULL;
+#endif /* HAVE_OCSP */
+
        return 0;
 }
 
@@ -2786,6 +3096,7 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
 {
        const EVP_CIPHER *c;
        const EVP_MD *h;
+       int md_size;
 
        if (conn == NULL || conn->ssl == NULL ||
            conn->ssl->enc_read_ctx == NULL ||
@@ -2799,9 +3110,20 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
 #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) +
-                   EVP_MD_size(h) +
+                   md_size +
                    EVP_CIPHER_iv_length(c));
 }
 
index a33d24e..2c2daa8 100644 (file)
@@ -2,14 +2,8 @@
  * SSL/TLS interface functions for Microsoft Schannel
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 /*
diff --git a/src/drivers/.gitignore b/src/drivers/.gitignore
new file mode 100644 (file)
index 0000000..1d9e0e6
--- /dev/null
@@ -0,0 +1,2 @@
+build.wpa_supplicant
+build.hostapd
index 53d1c25..d5b508d 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Driver interface definition
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
 #define HOSTAPD_CHAN_HT40MINUS 0x00000020
 #define HOSTAPD_CHAN_HT40 0x00000040
 
+#define HOSTAPD_CHAN_DFS_UNKNOWN 0x00000000
+#define HOSTAPD_CHAN_DFS_USABLE 0x00000100
+#define HOSTAPD_CHAN_DFS_UNAVAILABLE 0x00000200
+#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
+#define HOSTAPD_CHAN_DFS_MASK 0x00000300
+
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -47,7 +47,7 @@ struct hostapd_channel_data {
        /**
         * freq - Frequency in MHz
         */
-       short freq;
+       int freq;
 
        /**
         * flag - Channel flags (HOSTAPD_CHAN_*)
@@ -106,6 +106,16 @@ struct hostapd_hw_modes {
         */
        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_* */
 };
 
@@ -118,6 +128,13 @@ struct hostapd_hw_modes {
 #define IEEE80211_CAP_IBSS     0x0002
 #define IEEE80211_CAP_PRIVACY  0x0010
 
+/* DMG (60 GHz) IEEE 802.11ad */
+/* type - bits 0..1 */
+#define IEEE80211_CAP_DMG_MASK 0x0003
+#define IEEE80211_CAP_DMG_IBSS 0x0001 /* Tx by: STA */
+#define IEEE80211_CAP_DMG_PBSS 0x0002 /* Tx by: PCP */
+#define IEEE80211_CAP_DMG_AP   0x0003 /* Tx by: AP */
+
 #define WPA_SCAN_QUAL_INVALID          BIT(0)
 #define WPA_SCAN_NOISE_INVALID         BIT(1)
 #define WPA_SCAN_LEVEL_INVALID         BIT(2)
@@ -176,10 +193,12 @@ struct wpa_scan_res {
  * 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
+ * @fetch_time: Time when the results were fetched from the driver
  */
 struct wpa_scan_results {
        struct wpa_scan_res **res;
        size_t num;
+       struct os_time fetch_time;
 };
 
 /**
@@ -270,6 +289,15 @@ struct wpa_driver_scan_params {
        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
@@ -301,6 +329,9 @@ struct wpa_driver_auth_params {
         */
        int p2p;
 
+       const u8 *sae_data;
+       size_t sae_data_len;
+
 };
 
 enum wps_mode {
@@ -339,6 +370,13 @@ struct wpa_driver_associate_params {
        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
@@ -516,6 +554,39 @@ struct wpa_driver_associate_params {
         * 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 * */
+
+#ifdef CONFIG_VHT_OVERRIDES
+       /**
+        * disable_vht - Disable VHT for this connection
+        */
+       int disable_vht;
+
+       /**
+        * VHT capability overrides.
+        */
+       const struct ieee80211_vht_capabilities *vhtcaps;
+       const struct ieee80211_vht_capabilities *vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
 };
 
 enum hide_ssid {
@@ -693,6 +764,18 @@ struct wpa_driver_ap_params {
         * 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;
 };
 
 /**
@@ -706,12 +789,15 @@ struct wpa_driver_capa {
 #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
@@ -744,7 +830,7 @@ struct wpa_driver_capa {
  * 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 */
+/* This interface is P2P capable (P2P 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
@@ -776,6 +862,20 @@ struct wpa_driver_capa {
 #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
+/* Driver supports IBSS (Ad-hoc) mode */
+#define WPA_DRIVER_FLAGS_IBSS                          0x08000000
+/* Driver supports radar detection */
+#define WPA_DRIVER_FLAGS_RADAR                         0x10000000
+/* Driver supports a dedicated interface for P2P Device */
+#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE          0x20000000
        unsigned int flags;
 
        int max_scan_ssids;
@@ -807,6 +907,17 @@ struct wpa_driver_capa {
 /* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING     0x00000008
        unsigned int probe_resp_offloads;
+
+       unsigned int max_acl_mac_addrs;
+
+       /**
+        * extended_capa - extended capabilities in driver/device
+        *
+        * Must be allocated and freed by driver and the pointers must be
+        * valid for the lifetime of the driver, i.e., freed in deinit()
+        */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
 };
 
 
@@ -832,19 +943,41 @@ struct hostapd_sta_add_params {
        size_t supp_rates_len;
        u16 listen_interval;
        const struct ieee80211_ht_capabilities *ht_capabilities;
+       const struct ieee80211_vht_capabilities *vht_capabilities;
        u32 flags; /* bitmask of WPA_STA_* flags */
        int set; /* Set STA parameters instead of add */
        u8 qosinfo;
+       const u8 *ext_capab;
+       size_t ext_capab_len;
 };
 
 struct hostapd_freq_params {
        int mode;
        int freq;
        int channel;
+       /* for HT */
        int ht_enabled;
        int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
                                 * secondary channel below primary, 1 = HT40
                                 * enabled, secondary channel above primary */
+
+       /* for VHT */
+       int vht_enabled;
+
+       /* valid for both HT and VHT, center_freq2 is non-zero
+        * only for bandwidth 80 and an 80+80 channel */
+       int center_freq1, center_freq2;
+       int bandwidth;
+};
+
+struct mac_address {
+       u8 addr[ETH_ALEN];
+};
+
+struct hostapd_acl_params {
+       u8 acl_policy;
+       unsigned int num_mac_acl;
+       struct mac_address mac_acl[0];
 };
 
 enum wpa_driver_if_type {
@@ -882,7 +1015,13 @@ enum wpa_driver_if_type {
         * WPA_IF_P2P_GROUP - P2P Group interface (will become either
         * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
         */
-       WPA_IF_P2P_GROUP
+       WPA_IF_P2P_GROUP,
+
+       /**
+        * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+        * abstracted P2P Device function in the driver
+        */
+       WPA_IF_P2P_DEVICE
 };
 
 struct wpa_init_params {
@@ -942,6 +1081,34 @@ enum tdls_oper {
        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 */
+};
+
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+       CHAN_WIDTH_20_NOHT,
+       CHAN_WIDTH_20,
+       CHAN_WIDTH_40,
+       CHAN_WIDTH_80,
+       CHAN_WIDTH_80P80,
+       CHAN_WIDTH_160,
+       CHAN_WIDTH_UNKNOWN
+};
+
 /**
  * struct wpa_signal_info - Information about channel signal quality
  */
@@ -949,8 +1116,12 @@ struct wpa_signal_info {
        u32 frequency;
        int above_threshold;
        int current_signal;
+       int avg_signal;
        int current_noise;
        int current_txrate;
+       enum chan_width chanwidth;
+       int center_frq1;
+       int center_frq2;
 };
 
 /**
@@ -1001,7 +1172,8 @@ struct wpa_driver_ops {
         * @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_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
@@ -1018,11 +1190,11 @@ struct wpa_driver_ops {
         *      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: 6 octets, IGTK: 6 octets
+        *      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: 16, IGTK: 16)
+        *      TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
         *
         * Returns: 0 on success, -1 on failure
         *
@@ -1470,6 +1642,16 @@ struct wpa_driver_ops {
        int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
 
        /**
+        * set_acl - Set ACL in AP mode
+        * @priv: Private driver interface data
+        * @params: Parameters to configure ACL
+        * Returns: 0 on success, -1 on failure
+        *
+        * This is used only for the drivers which support MAC address ACL.
+        */
+       int (*set_acl)(void *priv, struct hostapd_acl_params *params);
+
+       /**
         * hapd_init - Initialize driver interface (hostapd only)
         * @hapd: Pointer to hostapd context
         * @params: Configuration for the driver wrapper
@@ -1527,9 +1709,9 @@ struct wpa_driver_ops {
         * 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).
+        * 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);
@@ -1562,7 +1744,7 @@ struct wpa_driver_ops {
        int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
 
        /**
-        * read_sta_data - Fetch station data (AP only)
+        * read_sta_data - Fetch station data
         * @priv: Private driver interface data
         * @data: Buffer for returning station information
         * @addr: MAC address of the station
@@ -1819,7 +2001,7 @@ struct wpa_driver_ops {
         * @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, 
+       int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
                                   u32 session_timeout);
 
        /**
@@ -1989,6 +2171,16 @@ struct wpa_driver_ops {
        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
         */
@@ -2348,6 +2540,18 @@ struct wpa_driver_ops {
        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
@@ -2483,6 +2687,62 @@ struct wpa_driver_ops {
         */
        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);
+
+       /**
+        * start_dfs_cac - Listen for radar interference on the channel
+        * @priv: Private driver interface data
+        * @freq: Frequency (in MHz) of the channel
+        * Returns: 0 on success, -1 on failure
+        */
+       int (*start_dfs_cac)(void *priv, int freq);
+
+       /**
+        * stop_ap - Removes beacon from AP
+        * @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. Unlike deinit_ap, it does not change to station
+        * mode.
+        */
+       int (*stop_ap)(void *priv);
+
+#ifdef TIZEN_EXT
+       /**
+        * priv_cmd - execute driver-specific command
+        * @priv: private driver interface data
+        * @cmd: command to execute
+        * @buf: return buffer
+        * @buf_len: buffer length
+        *
+        * Returns: 0 on success, -1 on failure
+        */
+       int (*priv_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif /* TIZEN_EXT */
 };
 
 
@@ -2913,7 +3173,61 @@ enum wpa_event_type {
        /**
         * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
         */
-       EVENT_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,
+
+       /**
+        * EVENT_CONNECT_FAILED_REASON - Connection failure reason in AP mode
+        *
+        * This event indicates that the driver reported a connection failure
+        * with the specified client (for example, max client reached, etc.) in
+        * AP mode.
+        */
+       EVENT_CONNECT_FAILED_REASON,
+
+       /**
+        * EVENT_RADAR_DETECTED - Notify of radar detection
+        *
+        * A radar has been detected on the supplied frequency, hostapd should
+        * react accordingly (e.g., change channel).
+        */
+       EVENT_DFS_RADAR_DETECTED,
+
+       /**
+        * EVENT_CAC_FINISHED - Notify that channel availability check has been completed
+        *
+        * After a successful CAC, the channel can be marked clear and used.
+        */
+       EVENT_DFS_CAC_FINISHED,
+
+       /**
+        * EVENT_CAC_ABORTED - Notify that channel availability check has been aborted
+        *
+        * The CAC was not successful, and the channel remains in the previous
+        * state. This may happen due to a radar beeing detected or other
+        * external influences.
+        */
+       EVENT_DFS_CAC_ABORTED,
+
+       /**
+        * EVENT_DFS_CAC_NOP_FINISHED - Notify that non-occupancy period is over
+        *
+        * The channel which was previously unavailable is now available again.
+        */
+       EVENT_DFS_NOP_FINISHED
 };
 
 
@@ -3028,6 +3342,11 @@ union wpa_event_data {
                 * 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;
 
        /**
@@ -3054,6 +3373,11 @@ union wpa_event_data {
                 * 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;
 
        /**
@@ -3106,6 +3430,24 @@ union wpa_event_data {
        } 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
@@ -3219,7 +3561,7 @@ union wpa_event_data {
                const u8 *frame;
                size_t frame_len;
                u32 datarate;
-               u32 ssi_signal;
+               int ssi_signal; /* dBm */
        } rx_mgmt;
 
        /**
@@ -3337,6 +3679,11 @@ union wpa_event_data {
                 * 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;
 
        /**
@@ -3493,6 +3840,39 @@ union wpa_event_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;
+
+       /**
+        * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
+        * @addr: Remote client address
+        * @code: Reason code for connection failure
+        */
+       struct connect_failed_reason {
+               u8 addr[ETH_ALEN];
+               enum {
+                       MAX_CLIENT_REACHED,
+                       BLOCKED_CLIENT
+               } code;
+       } connect_failed_reason;
+
+       /**
+        * struct dfs_event - Data for radar detected events
+        * @freq: Frequency of the channel in MHz
+        */
+       struct dfs_event {
+               int freq;
+       } dfs_event;
 };
 
 /**
index b17d1a6..c2f5934 100644 (file)
@@ -5,14 +5,8 @@
  * Copyright (c) 2005-2007, Jouni Malinen <j@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.
+ * 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 "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
 
 #ifdef CONFIG_WPS
 #include <netpacket/packet.h>
+#endif /* CONFIG_WPS */
 
 #ifndef ETH_P_80211_RAW
 #define ETH_P_80211_RAW 0x0019
 #endif
-#endif /* CONFIG_WPS */
 
 #include "linux_wext.h"
 
@@ -73,6 +73,7 @@ struct atheros_driver_data {
        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,
@@ -323,8 +324,7 @@ atheros_configure_wpa(struct atheros_driver_data *drv,
        }
 #endif /* CONFIG_IEEE80211W */
 
-       wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
-                  __func__, params->rsn_preauth);
+       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;
@@ -732,8 +732,8 @@ atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 }
 
 #ifdef CONFIG_WPS
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-                               size_t len)
+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;
@@ -762,28 +762,231 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 }
 #endif /* CONFIG_WPS */
 
-static int atheros_receive_probe_req(struct atheros_driver_data *drv)
+#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)
 {
-       int ret = 0;
 #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 = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
-       ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
-                          sizeof(struct ieee80211req_set_filter));
-       if (ret)
-               return ret;
+       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 */
+#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)
@@ -852,6 +1055,84 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
 #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])
 {
@@ -980,6 +1261,9 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                 * so all are enabled for WPS... ugh.
                 */
                wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
        } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
                /*
                 * Atheros driver uses a hack to pass Probe Request frames as a
@@ -987,16 +1271,134 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                 * 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) {
+               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 + WPS_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS */
+                                   (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;
        }
 }
 
@@ -1055,8 +1457,15 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
                                return;         /* XXX */
                        memcpy(buf, custom, iwe->u.data.length);
                        buf[iwe->u.data.length] = '\0';
-                       atheros_wireless_event_wireless_custom(
-                               drv, buf, buf + iwe->u.data.length);
+
+                       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;
                }
@@ -1245,6 +1654,7 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
                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]);
@@ -1278,13 +1688,17 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
        linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
        atheros_set_privacy(drv, 0); /* default to no privacy */
 
-       atheros_receive_probe_req(drv);
+       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)
@@ -1302,6 +1716,7 @@ 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)
@@ -1348,7 +1763,6 @@ atheros_get_ssid(void *priv, u8 *buf, int len)
        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;
        iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
                IW_ESSID_MAX_SIZE : len;
 
@@ -1421,6 +1835,290 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
        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,
@@ -1444,4 +2142,15 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
        .set_ap_wps_ie          = atheros_set_ap_wps_ie,
        .set_authmode           = atheros_set_authmode,
        .set_ap                 = atheros_set_ap,
+#ifdef CONFIG_IEEE80211R
+       .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 */
 };
index 4596a51..9d869b1 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2004, Sam Leffler <sam@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -979,13 +973,6 @@ wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
 }
 
 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;
@@ -1334,8 +1321,8 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
 
        result->ie_len = pos - (u8 *)(result + 1);
 
-       tmp = os_realloc(res->res,
-                        (res->num + 1) * sizeof(struct wpa_scan_res *));
+       tmp = os_realloc_array(res->res, res->num + 1,
+                              sizeof(struct wpa_scan_res *));
        if (tmp == NULL) {
                os_free(result);
                return;
@@ -1570,7 +1557,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .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 */
index 26ca8d6..12ccc14 100644 (file)
@@ -2,14 +2,8 @@
  * Common driver-related functions
  * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -83,6 +77,13 @@ const char * event_to_string(enum wpa_event_type event)
        E2S(SCHED_SCAN_STOPPED);
        E2S(DRIVER_CLIENT_POLL_OK);
        E2S(EAPOL_TX_STATUS);
+       E2S(CH_SWITCH);
+       E2S(WNM);
+       E2S(CONNECT_FAILED_REASON);
+       E2S(DFS_RADAR_DETECTED);
+       E2S(DFS_CAC_FINISHED);
+       E2S(DFS_CAC_ABORTED);
+       E2S(DFS_NOP_FINISHED);
        }
 
        return "UNKNOWN";
index 8fc0efd..16f5563 100644 (file)
@@ -2,14 +2,8 @@
  * Driver interaction with Linux Host AP driver
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 66b2bb3..a9d3e76 100644 (file)
@@ -2,14 +2,8 @@
  * Driver interaction with Linux Host AP driver
  * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HOSTAP_DRIVER_H
index edb086f..bb48011 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2004, Video54 Technologies
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index dbe9a28..4656c1b 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Windows/NDIS driver interface
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifdef __CYGWIN__
@@ -731,14 +725,6 @@ static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-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");
@@ -864,7 +850,7 @@ static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
                os_free(b);
                return NULL;
        }
-       results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
+       results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
        if (results->res == NULL) {
                os_free(results);
                os_free(b);
@@ -2124,14 +2110,8 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
                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';
-       }
-
+       drv->adapter_desc = dup_binstr(desc, dlen);
        os_free(b);
-
        if (drv->adapter_desc == NULL)
                return -1;
 
@@ -2298,14 +2278,8 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
        } 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';
-       }
-
+       drv->adapter_desc = dup_binstr(desc[i], dlen);
        os_free(names);
-
        if (drv->adapter_desc == NULL)
                return -1;
 
@@ -3229,7 +3203,6 @@ void driver_ndis_init_ops(void)
        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.disassociate = wpa_driver_ndis_disassociate;
        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;
index f263f0e..89d136d 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Windows/NDIS driver interface
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DRIVER_NDIS_H
index 4bee9aa..4d23001 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Windows/NDIS driver interface - event processing
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index bc8b1fc..a7af256 100644 (file)
@@ -1,19 +1,13 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #define PACKET_TX_TIMESTAMP    16
 #endif
 
+#ifdef TIZEN_EXT
+#ifdef BCM_DRIVER_V115
+#define GROUP_INTERFACE_PREFIX "p2p-wlan0"
+#endif
+#endif
+
 #ifdef ANDROID
 #include "android_drv.h"
 #endif /* ANDROID */
@@ -163,6 +163,8 @@ static void nl_destroy_handles(struct nl_handle **handle)
 struct nl80211_global {
        struct dl_list interfaces;
        int if_add_ifindex;
+       u64 if_add_wdevid;
+       int if_add_wdevid_set;
        struct netlink_data *netlink;
        struct nl_cb *nl_cb;
        struct nl_handle *nl;
@@ -184,22 +186,28 @@ struct nl80211_wiphy_data {
 };
 
 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;
+       u64 wdev_id;
        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;
+       unsigned int wdev_id_set:1;
 
        u8 addr[ETH_ALEN];
+#ifdef TIZEN_EXT_P2P
+       u8 dev_addr[ETH_ALEN];
+#endif /* TIZEN_EXT_P2P */
 
        int freq;
 
+       void *ctx;
        struct nl_handle *nl_preq, *nl_mgmt;
        struct nl_cb *nl_cb;
 
@@ -219,6 +227,8 @@ struct wpa_driver_nl80211_data {
        int ignore_if_down_event;
        struct rfkill_data *rfkill;
        struct wpa_driver_capa capa;
+       u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
        int has_capability;
 
        int operstate;
@@ -228,7 +238,9 @@ struct wpa_driver_nl80211_data {
        struct nl_cb *nl_cb;
 
        u8 auth_bssid[ETH_ALEN];
+       u8 auth_attempt_bssid[ETH_ALEN];
        u8 bssid[ETH_ALEN];
+       u8 prev_bssid[ETH_ALEN];
        int associated;
        u8 ssid[32];
        size_t ssid_len;
@@ -249,6 +261,8 @@ struct wpa_driver_nl80211_data {
        unsigned int scan_for_auth:1;
        unsigned int retry_auth:1;
        unsigned int use_monitor:1;
+       unsigned int ignore_next_local_disconnect:1;
+       unsigned int allow_p2p_device:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -289,6 +303,7 @@ struct wpa_driver_nl80211_data {
 };
 
 
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
                                            void *timeout_ctx);
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
@@ -304,7 +319,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len, u64 *cookie,
                                  int no_cck, int no_ack, int offchanok);
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
+                                              int report);
 #ifdef ANDROID
 static int android_pno_start(struct i802_bss *bss,
                             struct wpa_driver_scan_params *params);
@@ -315,7 +331,7 @@ static int android_pno_stop(struct i802_bss *bss);
 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,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
 #else /* HOSTAPD */
@@ -333,7 +349,8 @@ static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 #endif /* HOSTAPD */
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+                                      struct hostapd_freq_params *freq);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
                                     int ifindex, int disabled);
 
@@ -342,6 +359,117 @@ static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+       switch (cmd) {
+       C2S(NL80211_CMD_UNSPEC)
+       C2S(NL80211_CMD_GET_WIPHY)
+       C2S(NL80211_CMD_SET_WIPHY)
+       C2S(NL80211_CMD_NEW_WIPHY)
+       C2S(NL80211_CMD_DEL_WIPHY)
+       C2S(NL80211_CMD_GET_INTERFACE)
+       C2S(NL80211_CMD_SET_INTERFACE)
+       C2S(NL80211_CMD_NEW_INTERFACE)
+       C2S(NL80211_CMD_DEL_INTERFACE)
+       C2S(NL80211_CMD_GET_KEY)
+       C2S(NL80211_CMD_SET_KEY)
+       C2S(NL80211_CMD_NEW_KEY)
+       C2S(NL80211_CMD_DEL_KEY)
+       C2S(NL80211_CMD_GET_BEACON)
+       C2S(NL80211_CMD_SET_BEACON)
+       C2S(NL80211_CMD_START_AP)
+       C2S(NL80211_CMD_STOP_AP)
+       C2S(NL80211_CMD_GET_STATION)
+       C2S(NL80211_CMD_SET_STATION)
+       C2S(NL80211_CMD_NEW_STATION)
+       C2S(NL80211_CMD_DEL_STATION)
+       C2S(NL80211_CMD_GET_MPATH)
+       C2S(NL80211_CMD_SET_MPATH)
+       C2S(NL80211_CMD_NEW_MPATH)
+       C2S(NL80211_CMD_DEL_MPATH)
+       C2S(NL80211_CMD_SET_BSS)
+       C2S(NL80211_CMD_SET_REG)
+       C2S(NL80211_CMD_REQ_SET_REG)
+       C2S(NL80211_CMD_GET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+       C2S(NL80211_CMD_GET_REG)
+       C2S(NL80211_CMD_GET_SCAN)
+       C2S(NL80211_CMD_TRIGGER_SCAN)
+       C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCAN_ABORTED)
+       C2S(NL80211_CMD_REG_CHANGE)
+       C2S(NL80211_CMD_AUTHENTICATE)
+       C2S(NL80211_CMD_ASSOCIATE)
+       C2S(NL80211_CMD_DEAUTHENTICATE)
+       C2S(NL80211_CMD_DISASSOCIATE)
+       C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+       C2S(NL80211_CMD_REG_BEACON_HINT)
+       C2S(NL80211_CMD_JOIN_IBSS)
+       C2S(NL80211_CMD_LEAVE_IBSS)
+       C2S(NL80211_CMD_TESTMODE)
+       C2S(NL80211_CMD_CONNECT)
+       C2S(NL80211_CMD_ROAM)
+       C2S(NL80211_CMD_DISCONNECT)
+       C2S(NL80211_CMD_SET_WIPHY_NETNS)
+       C2S(NL80211_CMD_GET_SURVEY)
+       C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+       C2S(NL80211_CMD_SET_PMKSA)
+       C2S(NL80211_CMD_DEL_PMKSA)
+       C2S(NL80211_CMD_FLUSH_PMKSA)
+       C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+       C2S(NL80211_CMD_REGISTER_FRAME)
+       C2S(NL80211_CMD_FRAME)
+       C2S(NL80211_CMD_FRAME_TX_STATUS)
+       C2S(NL80211_CMD_SET_POWER_SAVE)
+       C2S(NL80211_CMD_GET_POWER_SAVE)
+       C2S(NL80211_CMD_SET_CQM)
+       C2S(NL80211_CMD_NOTIFY_CQM)
+       C2S(NL80211_CMD_SET_CHANNEL)
+       C2S(NL80211_CMD_SET_WDS_PEER)
+       C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+       C2S(NL80211_CMD_JOIN_MESH)
+       C2S(NL80211_CMD_LEAVE_MESH)
+       C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+       C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+       C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+       C2S(NL80211_CMD_GET_WOWLAN)
+       C2S(NL80211_CMD_SET_WOWLAN)
+       C2S(NL80211_CMD_START_SCHED_SCAN)
+       C2S(NL80211_CMD_STOP_SCHED_SCAN)
+       C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+       C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+       C2S(NL80211_CMD_PMKSA_CANDIDATE)
+       C2S(NL80211_CMD_TDLS_OPER)
+       C2S(NL80211_CMD_TDLS_MGMT)
+       C2S(NL80211_CMD_UNEXPECTED_FRAME)
+       C2S(NL80211_CMD_PROBE_CLIENT)
+       C2S(NL80211_CMD_REGISTER_BEACONS)
+       C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+       C2S(NL80211_CMD_SET_NOACK_MAP)
+       C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+       C2S(NL80211_CMD_START_P2P_DEVICE)
+       C2S(NL80211_CMD_STOP_P2P_DEVICE)
+       C2S(NL80211_CMD_CONN_FAILED)
+       C2S(NL80211_CMD_SET_MCAST_RATE)
+       C2S(NL80211_CMD_SET_MAC_ACL)
+       C2S(NL80211_CMD_RADAR_DETECT)
+       C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+       C2S(NL80211_CMD_UPDATE_FT_IES)
+       C2S(NL80211_CMD_FT_EVENT)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+       default:
+               return "NL80211_CMD_UNKNOWN";
+       }
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -356,13 +484,22 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
                nlmode == NL80211_IFTYPE_P2P_GO);
 }
 
 
+static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+       if (drv->associated)
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       drv->associated = 0;
+       os_memset(drv->bssid, 0, ETH_ALEN);
+}
+
+
 struct nl80211_bss_info_arg {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_scan_results *res;
@@ -464,6 +601,19 @@ struct family_data {
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+       if (bss->wdev_id_set)
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
        struct family_data *res = arg;
@@ -530,6 +680,8 @@ static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 
 struct wiphy_idx_data {
        int wiphy_idx;
+       enum nl80211_iftype nlmode;
+       u8 *macaddr;
 };
 
 
@@ -545,6 +697,13 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
        if (tb[NL80211_ATTR_WIPHY])
                info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
 
+       if (tb[NL80211_ATTR_IFTYPE])
+               info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+       if (tb[NL80211_ATTR_MAC] && info->macaddr)
+               os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
        return NL_SKIP;
 }
 
@@ -554,15 +713,17 @@ static int nl80211_get_wiphy_index(struct i802_bss *bss)
        struct nl_msg *msg;
        struct wiphy_idx_data data = {
                .wiphy_idx = -1,
+               .macaddr = NULL,
        };
 
        msg = nlmsg_alloc();
        if (!msg)
-               return -1;
+               return NL80211_IFTYPE_UNSPECIFIED;
 
        nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
 
        if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
                return data.wiphy_idx;
@@ -573,6 +734,57 @@ nla_put_failure:
 }
 
 
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .nlmode = NL80211_IFTYPE_UNSPECIFIED,
+               .macaddr = NULL,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+               return data.nlmode;
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+#ifndef HOSTAPD
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .macaddr = bss->addr,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return NL80211_IFTYPE_UNSPECIFIED;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+#endif /* HOSTAPD */
+
+
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
                                    struct nl80211_wiphy_data *w)
 {
@@ -606,7 +818,7 @@ static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
 {
        struct nl80211_wiphy_data *w = eloop_ctx;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available");
+       wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
 
        nl_recvmsgs(handle, w->nl_cb);
 }
@@ -789,10 +1001,28 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                   del ? "removed" : "added");
 
        if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
-               if (del)
+               if (del) {
+                       if (drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+                                          "already set - ignore event");
+                               return;
+                       }
                        drv->if_removed = 1;
-               else
+               } 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);
@@ -909,6 +1139,14 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                        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;
@@ -1002,6 +1240,7 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        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 "
@@ -1010,9 +1249,12 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        }
 
        os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+       os_memset(drv->auth_attempt_bssid, 0, 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;
@@ -1061,7 +1303,22 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 status;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Associate event");
        mgmt = (const struct ieee80211_mgmt *) frame;
+#ifdef TIZEN_EXT
+       if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) {
+               if (len < 24 + sizeof(mgmt->u.assoc_req)) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+                          "frame");
+                       return;
+               }
+               os_memset(&event, 0, sizeof(event));
+               event.assoc_info.freq = drv->assoc_freq;
+               event.assoc_info.req_ies = (u8 *) mgmt->u.assoc_req.variable;
+               event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req);
+               event.assoc_info.addr = mgmt->sa;
+       } else {
+#endif
        if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
                           "frame");
@@ -1086,6 +1343,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
 
        drv->associated = 1;
        os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+       os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
 
        os_memset(&event, 0, sizeof(event));
        if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -1095,7 +1353,9 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        }
 
        event.assoc_info.freq = drv->assoc_freq;
-
+#ifdef TIZEN_EXT
+       }
+#endif
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
@@ -1117,6 +1377,11 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                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) {
@@ -1132,8 +1397,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
        }
 
        drv->associated = 1;
-       if (addr)
+       if (addr) {
                os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       }
 
        if (req_ie) {
                event.assoc_info.req_ies = nla_data(req_ie);
@@ -1151,9 +1418,11 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
 
 
 static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
-                                 struct nlattr *reason, struct nlattr *addr)
+                                 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) {
                /*
@@ -1165,11 +1434,59 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
-       drv->associated = 0;
+       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");
+       nl80211_mark_disconnected(drv);
        os_memset(&data, 0, sizeof(data));
        if (reason)
-               data.disassoc_info.reason_code = nla_get_u16(reason);
-       wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+               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);
 }
 
 
@@ -1197,14 +1514,24 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
        wpa_supplicant_event(drv->ctx, ev, &event);
 }
 
+#ifdef TIZEN_EXT
+#ifdef BCM_DRIVER_V115
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+                                      enum wpa_event_type type,
+                                      const u8 *frame, size_t len);
+#endif
+#endif
 
 static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
-                           struct nlattr *freq, const u8 *frame, size_t len)
+                           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_MSGDUMP, "nl80211: Frame event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
@@ -1214,6 +1541,9 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        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);
@@ -1227,9 +1557,20 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
                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);
+#ifdef TIZEN_EXT
+#ifdef BCM_DRIVER_V115
+       } else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
+               mlme_event_assoc(drv, frame, len);
+       } else if (stype == WLAN_FC_STYPE_DISASSOC) {
+               mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, frame, len);
+       } else if (stype == WLAN_FC_STYPE_DEAUTH) {
+               mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, frame, len);
+#endif
+#endif
        } 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);
        }
 }
@@ -1243,6 +1584,7 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
        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;
 
@@ -1282,10 +1624,31 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        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->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+                   !drv->associated &&
+                   os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+                       /*
+                        * Avoid issues with some roaming cases where
+                        * disconnection event for the old AP may show up after
+                        * we have started connection with the new AP.
+                        */
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+                                  MAC2STR(bssid),
+                                  MAC2STR(drv->auth_attempt_bssid));
+                       return;
+               }
+
                if (drv->associated != 0 &&
                    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
                    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
@@ -1301,7 +1664,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                }
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(&event, 0, sizeof(event));
 
        /* Note: Same offset for Reason Code in both frame subtypes */
@@ -1309,6 +1672,14 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                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);
+#if (defined(TIZEN_EXT_P2P) || defined(TIZEN_EXT_SOFTAP)) && defined(BCM_DRIVER_V115)
+               if (drv->nlmode == NL80211_IFTYPE_AP ||
+                       drv->nlmode == NL80211_IFTYPE_P2P_GO) {
+                       event.disassoc_info.addr = mgmt->sa;
+               } else
+#endif
                event.disassoc_info.addr = bssid;
                event.disassoc_info.reason_code = reason_code;
                if (frame + len > mgmt->u.disassoc.variable) {
@@ -1317,6 +1688,14 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                                mgmt->u.disassoc.variable;
                }
        } else {
+               event.deauth_info.locally_generated =
+                       !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+#if (defined(TIZEN_EXT_P2P) || defined(TIZEN_EXT_SOFTAP)) && defined(BCM_DRIVER_V115)
+               if (drv->nlmode == NL80211_IFTYPE_AP ||
+                       drv->nlmode == NL80211_IFTYPE_P2P_GO) {
+               event.deauth_info.addr = mgmt->sa;
+               } else
+#endif
                event.deauth_info.addr = bssid;
                event.deauth_info.reason_code = reason_code;
                if (frame + len > mgmt->u.deauth.variable) {
@@ -1338,6 +1717,11 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
        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;
 
@@ -1362,24 +1746,69 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event(struct wpa_driver_nl80211_data *drv,
+static void mlme_event(struct i802_bss *bss,
                       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 *cookie, struct nlattr *sig)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       const u8 *data;
+       size_t len;
+
        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);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: MLME event %d (%s) without frame data",
+                          cmd, nl80211_command_to_string(cmd));
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+       data = nla_data(frame);
+       len = nla_len(frame);
+       if (len < 4 + 2 * ETH_ALEN) {
+               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+                          MACSTR ") - too short",
+                          cmd, nl80211_command_to_string(cmd), bss->ifname,
+                          MAC2STR(bss->addr));
+               return;
+       }
+       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+                  ") A1=" MACSTR " A2=" MACSTR, cmd,
+                  nl80211_command_to_string(cmd), bss->ifname,
+                  MAC2STR(bss->addr), MAC2STR(data + 4),
+                  MAC2STR(data + 4 + ETH_ALEN));
+#ifdef TIZEN_EXT_P2P
+       if (os_strstr(bss->ifname, GROUP_INTERFACE_PREFIX )== NULL){
+               if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+                       os_memcmp(bss->dev_addr, data + 4, ETH_ALEN) != 0 &&
+                       os_memcmp(bss->dev_addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+                       wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event on wlan0"
+                                  "for foreign address", bss->ifname);
+                       return;
+               }
+       }else{
+               if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+                       os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+                       os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+                       wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event on p2p"
+                                  "for foreign address", bss->ifname);
+                       return;
+               }
+       }
+#else /* TIZEN_EXT_P2P */
+       if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+           os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+           os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+               wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+                          "for foreign address", bss->ifname);
+               return;
+       }
+#endif /* TIZEN_EXT_P2P */
        wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
                    nla_data(frame), nla_len(frame));
 
@@ -1399,7 +1828,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
                                           nla_data(frame), nla_len(frame));
                break;
        case NL80211_CMD_FRAME:
-               mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(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),
@@ -1419,7 +1849,7 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
                                           struct nlattr *tb[])
 {
        union wpa_event_data data;
@@ -1451,7 +1881,7 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
                wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
        }
 
-       wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+       wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
 }
 
 
@@ -1520,6 +1950,34 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+                               struct nlattr *tb[])
+{
+       union wpa_event_data data;
+
+       os_memset(&data, 0, sizeof(data));
+
+       if (tb[NL80211_ATTR_IE]) {
+               data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+               data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+       }
+
+       if (tb[NL80211_ATTR_IE_RIC]) {
+               data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+               data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+       }
+
+       if (tb[NL80211_ATTR_MAC])
+               os_memcpy(data.ft_ies.target_ap,
+                         nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+                  MAC2STR(data.ft_ies.target_ap));
+
+       wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
 static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                            struct nlattr *tb[])
 {
@@ -1576,6 +2034,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
        static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
                [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
        };
        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1598,6 +2057,12 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        sig_change->current_signal =
                (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+       if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+               sig_change->avg_signal =
+                       (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+       else
+               sig_change->avg_signal = 0;
+
        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
                                     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1963,6 +2428,8 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
        };
        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,
@@ -1988,6 +2455,8 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 {
        union wpa_event_data data;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
        if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
                return;
 
@@ -1999,6 +2468,117 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+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_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+                                        struct nlattr **tb)
+{
+       union wpa_event_data data;
+       u32 reason;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.connect_failed_reason.addr,
+                 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+       switch (reason) {
+       case NL80211_CONN_FAIL_MAX_CLIENTS:
+               wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+               data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+               break;
+       case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+               wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+                          " tried to connect",
+                          MAC2STR(data.connect_failed_reason.addr));
+               data.connect_failed_reason.code = BLOCKED_CLIENT;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+                          "%u", reason);
+               return;
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+                               struct nlattr **tb)
+{
+       union wpa_event_data data;
+       enum nl80211_radar_event event_type;
+
+       if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+       event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+
+       wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+                  data.dfs_event.freq);
+
+       switch (event_type) {
+       case NL80211_RADAR_DETECTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+               break;
+       case NL80211_RADAR_CAC_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+               break;
+       case NL80211_RADAR_CAC_ABORTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+               break;
+       case NL80211_RADAR_NOP_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+                          "received", event_type);
+               break;
+       }
+}
+
+
 static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
                                   int wds)
 {
@@ -2017,9 +2597,14 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
 }
 
 
-static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
-                                int cmd, struct nlattr **tb)
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+                                struct nlattr **tb)
 {
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+                  cmd, nl80211_command_to_string(cmd), bss->ifname);
+
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2030,29 +2615,30 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
 
        switch (cmd) {
        case NL80211_CMD_TRIGGER_SCAN:
-               wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
                break;
        case NL80211_CMD_START_SCHED_SCAN:
-               wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
                break;
        case NL80211_CMD_SCHED_SCAN_STOPPED:
-               wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+               wpa_dbg(drv->ctx, 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");
+               wpa_dbg(drv->ctx, 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");
+               wpa_dbg(drv->ctx, 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");
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
                /*
                 * Need to indicate that scan results are available in order
                 * not to make wpa_supplicant stop its scanning.
@@ -2068,10 +2654,11 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
        case NL80211_CMD_FRAME_TX_STATUS:
        case NL80211_CMD_UNPROT_DEAUTHENTICATE:
        case NL80211_CMD_UNPROT_DISASSOCIATE:
-               mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
+               mlme_event(bss, 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_COOKIE],
+                          tb[NL80211_ATTR_RX_SIGNAL_DBM]);
                break;
        case NL80211_CMD_CONNECT:
        case NL80211_CMD_ROAM:
@@ -2081,12 +2668,17 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
                                   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_MAC],
+                                     tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
                break;
        case NL80211_CMD_MICHAEL_MIC_FAILURE:
-               mlme_event_michael_mic_failure(drv, tb);
+               mlme_event_michael_mic_failure(bss, tb);
                break;
        case NL80211_CMD_JOIN_IBSS:
                mlme_event_join_ibss(drv, tb);
@@ -2125,9 +2717,21 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
        case NL80211_CMD_PROBE_CLIENT:
                nl80211_client_probe_event(drv, tb);
                break;
+       case NL80211_CMD_TDLS_OPER:
+               nl80211_tdls_oper_event(drv, tb);
+               break;
+       case NL80211_CMD_CONN_FAILED:
+               nl80211_connect_failed_event(drv, tb);
+               break;
+       case NL80211_CMD_FT_EVENT:
+               mlme_event_ft_event(drv, tb);
+               break;
+       case NL80211_CMD_RADAR_DETECT:
+               nl80211_radar_event(drv, tb);
+               break;
        default:
-               wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
-                          "(cmd=%d)", cmd);
+               wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+                       "(cmd=%d)", cmd);
                break;
        }
 }
@@ -2138,21 +2742,37 @@ 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]) {
-               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;
+               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);
+       } else if (tb[NL80211_ATTR_WDEV]) {
+               u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
                }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+                          gnlh->cmd, (long long unsigned int) wdev_id);
        }
 
-       do_process_drv_event(drv, gnlh->cmd, tb);
        return NL_SKIP;
 }
 
@@ -2162,20 +2782,33 @@ 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;
+       struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
+       struct i802_bss *bss;
+       u64 wdev_id = 0;
+       int wdev_id_set = 0;
 
        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(drv, &global->interfaces,
-                        struct wpa_driver_nl80211_data, list) {
-               if (ifidx == -1 || ifidx == drv->ifindex ||
-                   have_ifidx(drv, ifidx))
-                       do_process_drv_event(drv, gnlh->cmd, tb);
+       else if (tb[NL80211_ATTR_WDEV]) {
+               wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wdev_id_set = 1;
+       }
+
+       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 && !wdev_id_set) ||
+                           ifidx == bss->ifindex ||
+                           (wdev_id_set && bss->wdev_id_set &&
+                            wdev_id == bss->wdev_id)) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               }
        }
 
        return NL_SKIP;
@@ -2191,13 +2824,18 @@ static int process_bss_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+                  gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+                  bss->ifname);
+
        switch (gnlh->cmd) {
        case NL80211_CMD_FRAME:
        case NL80211_CMD_FRAME_TX_STATUS:
-               mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+               mlme_event(bss, 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_COOKIE],
+                          tb[NL80211_ATTR_RX_SIGNAL_DBM]);
                break;
        case NL80211_CMD_UNEXPECTED_FRAME:
                nl80211_spurious_frame(bss, tb, 0);
@@ -2220,7 +2858,7 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 {
        struct nl_cb *cb = eloop_ctx;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+       wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
        nl_recvmsgs(handle, cb);
 }
@@ -2262,13 +2900,57 @@ nla_put_failure:
 }
 
 
-struct wiphy_info_data {
-       struct wpa_driver_capa *capa;
-
-       unsigned int error:1;
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+       u32 *feat = arg;
+       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+               *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+       return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+       u32 feat = 0;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               goto nla_put_failure;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
+       if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+               return feat;
+
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return 0;
+}
+
+
+struct wiphy_info_data {
+       struct wpa_driver_nl80211_data *drv;
+       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;
+       unsigned int auth_supported:1;
+       unsigned int connect_supported:1;
+       unsigned int p2p_go_supported:1;
+       unsigned int p2p_client_supported:1;
+       unsigned int p2p_concurrent:1;
+       unsigned int p2p_multichan_concurrent:1;
 };
 
 
@@ -2289,30 +2971,228 @@ static unsigned int probe_resp_offload_support(int supp_protocols)
 }
 
 
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+                                        struct nlattr *tb)
 {
-       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;
-       int auth_supported = 0, connect_supported = 0;
-       struct wpa_driver_capa *capa = info->capa;
+       struct nlattr *nl_mode;
+       int i;
+
+       if (tb == NULL)
+               return;
+
+       nla_for_each_nested(nl_mode, tb, i) {
+               switch (nla_type(nl_mode)) {
+               case NL80211_IFTYPE_AP:
+                       info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+                       break;
+               case NL80211_IFTYPE_ADHOC:
+                       info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+                       break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       info->capa->flags |=
+                               WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+                       break;
+               case NL80211_IFTYPE_P2P_GO:
+                       info->p2p_go_supported = 1;
+                       break;
+               case NL80211_IFTYPE_P2P_CLIENT:
+                       info->p2p_client_supported = 1;
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       info->monitor_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+                                        struct nlattr *nl_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;
        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 },
+               [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
        },
        iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
                [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
                [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
        };
 
+       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])
+               return 0; /* broken combination */
+
+       if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+               info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
+       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])
+                       return 0; /* 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) {
+               info->p2p_concurrent = 1;
+               if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+                       info->p2p_multichan_concurrent = 1;
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+                                 struct nlattr *tb)
+{
+       struct nlattr *nl_combi;
+       int rem_combi;
+
+       if (tb == NULL)
+               return;
+
+       nla_for_each_nested(nl_combi, tb, rem_combi) {
+               if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+                       break;
+       }
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+                                struct nlattr *tb)
+{
+       struct nlattr *nl_cmd;
+       int i;
+
+       if (tb == NULL)
+               return;
+
+       nla_for_each_nested(nl_cmd, tb, i) {
+               switch (nla_get_u32(nl_cmd)) {
+               case NL80211_CMD_AUTHENTICATE:
+                       info->auth_supported = 1;
+                       break;
+               case NL80211_CMD_CONNECT:
+                       info->connect_supported = 1;
+                       break;
+               case NL80211_CMD_START_SCHED_SCAN:
+                       info->capa->sched_scan_supported = 1;
+                       break;
+               case NL80211_CMD_PROBE_CLIENT:
+                       info->poll_command_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+                              struct nlattr *tb)
+{
+       if (tb)
+               capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+                           struct nlattr *ext_setup)
+{
+       if (tdls == NULL)
+               return;
+
+       wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+       capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+       if (ext_setup) {
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+               capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+       }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+                                    struct nlattr *tb)
+{
+       u32 flags;
+       struct wpa_driver_capa *capa = info->capa;
+
+       if (tb == NULL)
+               return;
+
+       flags = nla_get_u32(tb);
+
+       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;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+                                         struct nlattr *tb)
+{
+       u32 protocols;
+
+       if (tb == NULL)
+               return;
+
+       protocols = nla_get_u32(tb);
+       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);
+}
+
+
+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;
+       struct wpa_driver_capa *capa = info->capa;
+       struct wpa_driver_nl80211_data *drv = info->drv;
+
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       if (tb[NL80211_ATTR_WIPHY_NAME])
+               os_strncpy(drv->phyname,
+                          nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+                          sizeof(drv->phyname));
        if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
                capa->max_scan_ssids =
                        nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
@@ -2325,104 +3205,13 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                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;
-                       }
-               }
-       }
-
-       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;
-                               break;
-                       }
+       if (tb[NL80211_ATTR_MAC_ACL_MAX])
+               capa->max_acl_mac_addrs =
+                       nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
 
-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;
-                       }
-               }
-       }
+       wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+       wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+       wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
 
        if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
                wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -2435,62 +3224,44 @@ broken_combination:
                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;
+       wiphy_info_max_roc(capa,
+                          tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
 
        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 (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;
-               }
-       }
+       wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+                       tb[NL80211_ATTR_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 (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);
+       wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+       wiphy_info_probe_resp_offload(capa,
+                                     tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+       if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+           drv->extended_capa == NULL) {
+               drv->extended_capa =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa) {
+                       os_memcpy(drv->extended_capa,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+                       drv->extended_capa_len =
+                               nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+               }
+               drv->extended_capa_mask =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa_mask) {
+                       os_memcpy(drv->extended_capa_mask,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               } else {
+                       os_free(drv->extended_capa);
+                       drv->extended_capa = NULL;
+                       drv->extended_capa_len = 0;
+               }
        }
 
        return NL_SKIP;
@@ -2500,22 +3271,62 @@ broken_combination:
 static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                                       struct wiphy_info_data *info)
 {
+       u32 feat;
        struct nl_msg *msg;
 
        os_memset(info, 0, sizeof(*info));
        info->capa = &drv->capa;
+       info->drv = drv;
 
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+       feat = get_nl80211_protocol_features(drv);
+       if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+               nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+
+       NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
+       if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+               return -1;
 
-       if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
-               return 0;
-       msg = NULL;
+       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");
+               info->error = 1;
+       }
+
+       if (info->p2p_go_supported && info->p2p_client_supported)
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+       if (info->p2p_concurrent) {
+               wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+                          "interface (driver advertised support)");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+       }
+       if (info->p2p_multichan_concurrent) {
+               wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+                          "concurrent (driver advertised support)");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+       }
+
+       /* default to 5000 since early versions of mac80211 don't set it */
+       if (!drv->capa.max_remain_on_chan)
+               drv->capa.max_remain_on_chan = 5000;
+#ifdef TIZEN_EXT
+#ifdef BCM_DRIVER_V115
+       info->device_ap_sme = 1;
+#endif
+#endif
+
+       return 0;
 nla_put_failure:
        nlmsg_free(msg);
        return -1;
@@ -2548,17 +3359,41 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        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;
-       drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_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 is supported mac80211 is new enough to
-        * have everything we need to not need monitor interfaces.
+        * 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;
+       //drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+       drv->use_monitor = 0;
+
+       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
@@ -2572,6 +3407,42 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 }
 
 
+#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;
@@ -2689,39 +3560,6 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 }
 
 
-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)
@@ -2730,10 +3568,7 @@ static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
        u8 data[2048];
        struct msghdr msg;
        struct iovec entry;
-       struct {
-               struct cmsghdr cm;
-               char control[512];
-       } control;
+       u8 control[512];
        struct cmsghdr *cmsg;
        int res, found_ee = 0, found_wifi = 0, acked = 0;
        union wpa_event_data event;
@@ -2830,6 +3665,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        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;
@@ -2844,8 +3681,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        if (nl80211_init_bss(bss))
                goto failed;
 
-       nl80211_get_phy_name(drv);
-
        rcfg = os_zalloc(sizeof(*rcfg));
        if (rcfg == NULL)
                goto failed;
@@ -2909,9 +3744,16 @@ static int nl80211_register_frame(struct i802_bss *bss,
        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);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -2938,7 +3780,7 @@ static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
 
        if (bss->nl_mgmt) {
                wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
-                          "already on!");
+                          "already on! (nl_mgmt=%p)", bss->nl_mgmt);
                return -1;
        }
 
@@ -2969,6 +3811,8 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 
        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 */
@@ -3020,6 +3864,9 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        /* 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;
 }
@@ -3075,6 +3922,8 @@ static int nl80211_mgmt_subscribe_ap(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", bss->nl_mgmt);
 
        for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
                if (nl80211_register_frame(bss, bss->nl_mgmt,
@@ -3100,10 +3949,34 @@ out_err:
 }
 
 
-static void nl80211_mgmt_unsubscribe(struct i802_bss *bss)
+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);
 
@@ -3117,27 +3990,124 @@ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+       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_DEL_INTERFACE);
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       if (start)
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+                  start ? "Start" : "Stop",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+       enum nl80211_iftype nlmode;
+
+       nlmode = nl80211_get_ifmode(bss);
+       if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+                                            bss->ifname, up);
+       }
+
+       /* P2P Device has start/stop which is equivalent */
+       return nl80211_set_p2pdev(bss, up);
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
+#ifndef HOSTAPD
+       enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
+#endif /* HOSTAPD */
        struct i802_bss *bss = &drv->first_bss;
        int send_rfkill_event = 0;
+       int dynamic_if;
 
        drv->ifindex = if_nametoindex(bss->ifname);
-       drv->first_bss.ifindex = drv->ifindex;
+       bss->ifindex = drv->ifindex;
+       bss->wdev_id = drv->global->if_add_wdevid;
+       bss->wdev_id_set = drv->global->if_add_wdevid_set;
+
+       dynamic_if = drv->ifindex == drv->global->if_add_ifindex;
+       dynamic_if = dynamic_if || drv->global->if_add_wdevid_set;
+       drv->global->if_add_wdevid_set = 0;
+
+       if (wpa_driver_nl80211_capa(drv))
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+                  bss->ifname, drv->phyname);
 
 #ifndef HOSTAPD
+       if (dynamic_if)
+               nlmode = nl80211_get_ifmode(bss);
+
        /*
         * 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");
+       if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
                return -1;
        }
+       drv->nlmode = nlmode;
+
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               int ret = nl80211_set_p2pdev(bss, 1);
+               if (ret < 0)
+                       wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+               nl80211_get_macaddr(bss);
+               return ret;
+       }
 
        if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
                if (rfkill_is_blocked(drv->rfkill)) {
@@ -3157,13 +4127,19 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                               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;
 
+#ifdef TIZEN_EXT_P2P
+#ifdef BCM_DRIVER_V115
+       int wpa_driver_nl80211_priv_cmd_bcm(void *priv, char *cmd, char *buf,
+                       size_t buf_len );
+       char buf[64];
+       wpa_driver_nl80211_priv_cmd_bcm(bss,"P2P_DEV_ADDR",buf, sizeof(buf));
+       os_memcpy(bss->dev_addr, buf, ETH_ALEN);
+#endif /* BCM_DRIVER_V115 */
+#endif /* TIZEN_EXT_P2P */
        if (send_rfkill_event) {
                eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
                                       drv, drv->ctx);
@@ -3193,16 +4169,16 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 
 /**
  * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
  *
  * Shut down driver interface and processing of driver events. Free
  * private data buffer if one was allocated in wpa_driver_nl80211_init().
  */
-static void wpa_driver_nl80211_deinit(void *priv)
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
-       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)
@@ -3235,7 +4211,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
                struct hostapd_freq_params freq;
                os_memset(&freq, 0, sizeof(freq));
                freq.freq = drv->last_freq;
-               i802_set_freq(priv, &freq);
+               wpa_driver_nl80211_set_freq(bss, &freq);
        }
 
        if (drv->eapol_sock >= 0) {
@@ -3256,10 +4232,13 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        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);
-
+       (void) i802_set_iface_flags(bss, 0);
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+       } else {
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+               nl80211_del_p2pdev(bss);
+       }
        nl_cb_put(drv->nl_cb);
 
        nl80211_destroy_bss(&drv->first_bss);
@@ -3271,6 +4250,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
        os_free(drv);
 }
 
@@ -3296,80 +4277,116 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-/**
- * 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)
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = 0, timeout;
-       struct nl_msg *msg, *ssids, *freqs, *rates;
+       struct nl_msg *msg;
        size_t i;
 
-       drv->scan_for_auth = 0;
-
        msg = nlmsg_alloc();
-       ssids = nlmsg_alloc();
-       freqs = nlmsg_alloc();
-       rates = nlmsg_alloc();
-       if (!msg || !ssids || !freqs || !rates) {
-               nlmsg_free(msg);
-               nlmsg_free(ssids);
-               nlmsg_free(freqs);
-               nlmsg_free(rates);
-               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;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
+       if (!msg)
+               return NULL;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       nl80211_cmd(drv, msg, 0, cmd);
 
-       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 (!wdev_id)
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       else
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
+
+       if (params->num_ssids) {
+               struct nlattr *ssids;
+
+               ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+               if (ssids == NULL)
+                       goto fail;
+               for (i = 0; i < params->num_ssids; i++) {
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+                                         params->ssids[i].ssid,
+                                         params->ssids[i].ssid_len);
+                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+                                   params->ssids[i].ssid) < 0)
+                               goto fail;
+               }
+               nla_nest_end(msg, ssids);
        }
-       if (params->num_ssids)
-               nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
        if (params->extra_ies) {
                wpa_hexdump(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 (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+                           params->extra_ies) < 0)
+                       goto fail;
        }
 
        if (params->freqs) {
+               struct nlattr *freqs;
+               freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+               if (freqs == NULL)
+                       goto fail;
                for (i = 0; params->freqs[i]; i++) {
                        wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
                                   "MHz", params->freqs[i]);
-                       NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+                       if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
+                               goto fail;
                }
-               nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+               nla_nest_end(msg, freqs);
        }
 
-       if (params->p2p_probe) {
+       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:
+nla_put_failure:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: 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(struct i802_bss *bss,
+                                  struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int ret = -1, timeout;
+       struct nl_msg *msg = NULL;
+
+       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+       drv->scan_for_auth = 0;
+
+       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
+       if (!msg)
+               return -1;
+
+       if (params->p2p_probe) {
+               struct nlattr *rates;
+
+               wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+               rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+               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,
+               NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
                        "\x0c\x12\x18\x24\x30\x48\x60\x6c");
-               nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+               nla_nest_end(msg, rates);
 
                NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
        }
@@ -3389,7 +4406,7 @@ static int wpa_driver_nl80211_scan(void *priv,
                                    bss, NL80211_IFTYPE_STATION))
                                goto nla_put_failure;
 
-                       if (wpa_driver_nl80211_scan(drv, params)) {
+                       if (wpa_driver_nl80211_scan(bss, params)) {
                                wpa_driver_nl80211_set_mode(bss, drv->nlmode);
                                goto nla_put_failure;
                        }
@@ -3422,10 +4439,7 @@ static int wpa_driver_nl80211_scan(void *priv,
                               drv, drv->ctx);
 
 nla_put_failure:
-       nlmsg_free(ssids);
        nlmsg_free(msg);
-       nlmsg_free(freqs);
-       nlmsg_free(rates);
        return ret;
 }
 
@@ -3443,86 +4457,63 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ret = 0;
-       struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+       int ret = -1;
+       struct nl_msg *msg;
        size_t i;
 
+       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
 #ifdef ANDROID
        if (!drv->capa.sched_scan_supported)
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-       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;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
+       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) {
-               match_sets = nlmsg_alloc();
+       if ((drv->num_filter_ssids &&
+           (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+           params->filter_rssi) {
+               struct nlattr *match_sets;
+               match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+               if (match_sets == NULL)
+                       goto nla_put_failure;
 
                for (i = 0; i < drv->num_filter_ssids; i++) {
+                       struct nlattr *match_set_ssid;
                        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();
-                       nla_put(match_set_ssid,
-                               NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+                       match_set_ssid = nla_nest_start(msg, i + 1);
+                       if (match_set_ssid == NULL)
+                               goto nla_put_failure;
+                       NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
                                drv->filter_ssids[i].ssid_len,
                                drv->filter_ssids[i].ssid);
 
-                       nla_put_nested(match_sets, i + 1, match_set_ssid);
-
-                       nlmsg_free(match_set_ssid);
+                       nla_nest_end(msg, match_set_ssid);
                }
 
-               nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-                              match_sets);
-               nlmsg_free(match_sets);
-       }
-
-       for (i = 0; i < params->num_ssids; i++) {
-               wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched 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: Sched 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]);
+               if (params->filter_rssi) {
+                       struct nlattr *match_set_rssi;
+                       match_set_rssi = nla_nest_start(msg, 0);
+                       if (match_set_rssi == NULL)
+                               goto nla_put_failure;
+                       NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+                                   params->filter_rssi);
+                       wpa_printf(MSG_MSGDUMP,
+                                  "nl80211: Sched scan RSSI filter %d dBm",
+                                  params->filter_rssi);
+                       nla_nest_end(msg, match_set_rssi);
                }
-               nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+               nla_nest_end(msg, match_sets);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3540,9 +4531,7 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-       nlmsg_free(ssids);
        nlmsg_free(msg);
-       nlmsg_free(freqs);
        return ret;
 }
 
@@ -3790,8 +4779,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                return NL_SKIP;
        }
 
-       tmp = os_realloc(res->res,
-                        (res->num + 1) * sizeof(struct wpa_scan_res *));
+       tmp = os_realloc_array(res->res, res->num + 1,
+                              sizeof(struct wpa_scan_res *));
        if (tmp == NULL) {
                os_free(r);
                return NL_SKIP;
@@ -3883,7 +4872,8 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
                goto nla_put_failure;
 
        nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
 
        arg.drv = drv;
        arg.res = res;
@@ -3947,21 +4937,25 @@ static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
 }
 
 
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      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);
+       int ifindex;
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+       /* Ignore for P2P Device */
+       if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
+
+       ifindex = if_nametoindex(ifname);
+       wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
                   "set_tx=%d seq_len=%lu key_len=%lu",
-                  __func__, ifindex, alg, addr, key_idx, set_tx,
+                  __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
        if (key_idx == -1)
@@ -3994,10 +4988,22 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                        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);
@@ -4019,18 +5025,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                                    NL80211_KEYTYPE_GROUP);
                }
        } else if (addr && is_broadcast_ether_addr(addr)) {
-               struct nl_msg *types;
-               int err;
+               struct nlattr *types;
+
                wpa_printf(MSG_DEBUG, "   broadcast key");
-               types = nlmsg_alloc();
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                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_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        }
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4064,29 +5067,21 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
        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();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                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_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        } else if (addr) {
-               struct nl_msg *types;
-               int err;
-               types = nlmsg_alloc();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                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;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+               nla_nest_end(msg, types);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4134,6 +5129,9 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        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);
@@ -4232,7 +5230,8 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 
        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 (addr)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        if (local_state_change)
                NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
 
@@ -4253,26 +5252,26 @@ nla_put_failure:
 
 
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                                        const u8 *addr, int reason_code)
+                                        int reason_code)
 {
-       wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
-                  __func__, MAC2STR(addr), reason_code);
-       drv->associated = 0;
-       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+       wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
+       nl80211_mark_disconnected(drv);
+       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)
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+                                            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);
+               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;
+       nl80211_mark_disconnected(drv);
        if (drv->nlmode == NL80211_IFTYPE_ADHOC)
                return nl80211_leave_ibss(drv);
        return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
@@ -4280,20 +5279,6 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-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 void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
                                     struct wpa_driver_auth_params *params)
 {
@@ -4341,9 +5326,8 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
 
 
 static int wpa_driver_nl80211_authenticate(
-       void *priv, struct wpa_driver_auth_params *params)
+       struct i802_bss *bss, 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;
@@ -4355,13 +5339,21 @@ static int wpa_driver_nl80211_authenticate(
        is_retry = drv->retry_auth;
        drv->retry_auth = 0;
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(drv->auth_bssid, 0, ETH_ALEN);
+       if (params->bssid)
+               os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+       else
+               os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
        /* FIX: IBSS mode */
+#ifdef TIZEN_EXT_P2P
+       nlmode = NL80211_IFTYPE_STATION;
+#else
        nlmode = params->p2p ?
                NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+#endif
        if (drv->nlmode != nlmode &&
-           wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+           wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
                return -1;
 
 retry:
@@ -4377,7 +5369,7 @@ retry:
        for (i = 0; i < 4; i++) {
                if (!params->wep_key[i])
                        continue;
-               wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+               wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
                                           NULL, i,
                                           i == params->wep_tx_keyidx, NULL, 0,
                                           params->wep_key[i],
@@ -4410,6 +5402,12 @@ retry:
        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)
@@ -4418,6 +5416,8 @@ retry:
                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);
@@ -4546,17 +5546,91 @@ static int wpa_driver_nl80211_authenticate_retry(
 struct phy_info_arg {
        u16 *num_modes;
        struct hostapd_hw_modes *modes;
+       int last_mode, last_chan_idx;
 };
 
-static int phy_info_handler(struct nl_msg *msg, void *arg)
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+                            struct nlattr *ampdu_factor,
+                            struct nlattr *ampdu_density,
+                            struct nlattr *mcs_set)
 {
-       struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-       struct phy_info_arg *phy_info = arg;
+       if (capa)
+               mode->ht_capab = nla_get_u16(capa);
 
-       struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+       if (ampdu_factor)
+               mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
 
-       struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+       if (ampdu_density)
+               mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+       if (mcs_set && nla_len(mcs_set) >= 16) {
+               u8 *mcs;
+               mcs = nla_data(mcs_set);
+               os_memcpy(mode->mcs_set, mcs, 16);
+       }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+                             struct nlattr *capa,
+                             struct nlattr *mcs_set)
+{
+       if (capa)
+               mode->vht_capab = nla_get_u32(capa);
+
+       if (mcs_set && nla_len(mcs_set) >= 8) {
+               u8 *mcs;
+               mcs = nla_data(mcs_set);
+               os_memcpy(mode->vht_mcs_set, mcs, 8);
+       }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+                         struct hostapd_channel_data *chan,
+                         struct nlattr *tb_freq[])
+{
+       u8 channel;
+       chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+       chan->flag = 0;
+       if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+               chan->chan = channel;
+
+       if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+               chan->flag |= HOSTAPD_CHAN_DISABLED;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+               chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+               chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+               chan->flag |= HOSTAPD_CHAN_RADAR;
+
+       if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+           !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+               chan->max_tx_power = nla_get_u32(
+                       tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+               enum nl80211_dfs_state state =
+                       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+               switch (state) {
+               case NL80211_DFS_USABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+                       break;
+               case NL80211_DFS_AVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+                       break;
+               case NL80211_DFS_UNAVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+                       break;
+               }
+       }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+                         struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
        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 },
@@ -4564,169 +5638,189 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
                [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+               [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .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;
+       int new_channels = 0;
+       struct hostapd_channel_data *channel;
+       struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
        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;
+       int rem_freq, idx;
 
-       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (tb == NULL)
+               return NL_OK;
 
-       if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+       nla_for_each_nested(nl_freq, tb, 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;
+               new_channels++;
+       }
+
+       channel = os_realloc_array(mode->channels,
+                                  mode->num_channels + new_channels,
+                                  sizeof(struct hostapd_channel_data));
+       if (!channel)
                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->channels = channel;
+       mode->num_channels += new_channels;
 
-               mode_is_set = 0;
+       idx = phy_info->last_chan_idx;
 
-               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_for_each_nested(nl_freq, tb, 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;
+               phy_info_freq(mode, &mode->channels[idx], tb_freq);
+               idx++;
+       }
+       phy_info->last_chan_idx = idx;
 
-               nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
-                         nla_len(nl_band), NULL);
+       return NL_OK;
+}
 
-               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;
-               }
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+       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 *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+       struct nlattr *nl_rate;
+       int rem_rate, idx;
 
-               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 == NULL)
+               return NL_OK;
 
-               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_rate, tb, 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++;
+       }
 
-               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->rates = os_calloc(mode->num_rates, sizeof(int));
+       if (!mode->rates)
+               return NL_SKIP;
 
-               mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
-               if (!mode->channels)
-                       return NL_SKIP;
+       idx = 0;
 
-               idx = 0;
+       nla_for_each_nested(nl_rate, tb, 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]);
+               idx++;
+       }
 
-               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;
+       return NL_OK;
+}
 
-                       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;
-                       }
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+       struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+       struct hostapd_hw_modes *mode;
+       int ret;
 
-                       /* 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++;
-               }
+       if (phy_info->last_mode != nl_band->nla_type) {
+               mode = os_realloc_array(phy_info->modes,
+                                       *phy_info->num_modes + 1,
+                                       sizeof(*mode));
+               if (!mode)
+                       return NL_SKIP;
+               phy_info->modes = mode;
 
-               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 = &phy_info->modes[*(phy_info->num_modes)];
+               os_memset(mode, 0, sizeof(*mode));
+               mode->mode = NUM_HOSTAPD_MODES;
+               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
+               *(phy_info->num_modes) += 1;
+               phy_info->last_mode = nl_band->nla_type;
+               phy_info->last_chan_idx = 0;
+       } else
+               mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+       nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+                 nla_len(nl_band), NULL);
+
+       phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+                        tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+                        tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+                        tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+       phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+                         tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+       ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+       if (ret != NL_OK)
+               return ret;
+       ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+       if (ret != NL_OK)
+               return ret;
+
+       return NL_OK;
+}
 
-               mode->rates = os_zalloc(mode->num_rates * sizeof(int));
-               if (!mode->rates)
-                       return NL_SKIP;
 
-               idx = 0;
+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 *nl_band;
+       int rem_band;
 
-               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]);
+       nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
 
-                       /* crude heuristic */
-                       if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
-                           mode->rates[idx] > 200)
-                               mode->mode = HOSTAPD_MODE_IEEE80211G;
+       if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+               return NL_SKIP;
 
-                       idx++;
-               }
+       nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+       {
+               int res = phy_info_band(phy_info, nl_band);
+               if (res != NL_OK)
+                       return res;
        }
 
        return NL_SKIP;
 }
 
+
 static struct hostapd_hw_modes *
-wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+                                    u16 *num_modes)
 {
        u16 m;
        struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
        int i, mode11g_idx = -1;
 
+       /* heuristic to set up modes */
+       for (m = 0; m < *num_modes; m++) {
+               if (!modes[m].num_channels)
+                       continue;
+               if (modes[m].channels[0].freq < 4000) {
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+                       for (i = 0; i < modes[m].num_rates; i++) {
+                               if (modes[m].rates[i] > 200) {
+                                       modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+                                       break;
+                               }
+                       }
+               } else if (modes[m].channels[0].freq > 50000)
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+               else
+                       modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+       }
+
        /* If only 802.11g mode is included, use it to construct matching
         * 802.11b mode data. */
 
@@ -4740,7 +5834,7 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
        if (mode11g_idx < 0)
                return modes; /* 2.4 GHz band not supported at all */
 
-       nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+       nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
        if (nmodes == NULL)
                return modes; /* Could not add 802.11b mode */
 
@@ -4944,12 +6038,14 @@ static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
 static struct hostapd_hw_modes *
 wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 {
+       u32 feat;
        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,
+               .last_mode = -1,
        };
 
        *num_modes = 0;
@@ -4959,13 +6055,19 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        if (!msg)
                return NULL;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+       feat = get_nl80211_protocol_features(drv);
+       if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+               nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
+       NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
        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);
+               return wpa_driver_nl80211_postprocess_modes(result.modes,
+                                                           num_modes);
        }
        msg = NULL;
  nla_put_failure:
@@ -5020,7 +6122,7 @@ static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
 
        if (noack)
                txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
-       *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+       WPA_PUT_LE16(&rtap_hdr[12], txflags);
 
        res = sendmsg(drv->monitor_sock, &msg, 0);
        if (res < 0) {
@@ -5033,24 +6135,31 @@ static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
 
 static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
                                         const void *data, size_t len,
-                                        int encrypt, int noack)
+                                        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, bss->freq, 0, data, len,
-                                     &cookie, 0, noack, 0);
+       return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+                                     &cookie, no_cck, noack, offchanok);
 }
 
 
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                       size_t data_len, int noack)
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+                                       size_t data_len, int noack,
+                                       unsigned int freq, int no_cck,
+                                       int offchanok,
+                                       unsigned int wait_time)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt *mgmt;
        int encrypt = 1;
@@ -5059,7 +6168,8 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
        mgmt = (struct ieee80211_mgmt *) data;
        fc = le_to_host16(mgmt->frame_control);
 
-       if (is_sta_interface(drv->nlmode) &&
+       if ((is_sta_interface(drv->nlmode) ||
+            drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
            WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
            WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
                /*
@@ -5067,15 +6177,22 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                 * but it works due to the single-threaded nature
                 * of wpa_supplicant.
                 */
-               return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0,
+               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)) {
-               return nl80211_send_frame_cmd(bss, bss->freq, 0,
-                                             data, data_len, NULL,
-                                             0, noack, 0);
+               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 &&
@@ -5093,7 +6210,8 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
        }
 
        return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
-                                            noack);
+                                            noack, freq, no_cck, offchanok,
+                                            wait_time);
 }
 
 
@@ -5142,6 +6260,60 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 }
 
 
+static int wpa_driver_nl80211_set_acl(void *priv,
+                                     struct hostapd_acl_params *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *acl;
+       unsigned int i;
+       int ret = 0;
+
+       if (!(drv->capa.max_acl_mac_addrs))
+               return -ENOTSUP;
+
+       if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+               return -ENOTSUP;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+                  params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+                   NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+                   NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+       acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+       if (acl == NULL)
+               goto nla_put_failure;
+
+       for (i = 0; i < params->num_mac_acl; i++)
+               NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+       nla_nest_end(msg, acl);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+nla_put_failure:
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -5168,32 +6340,49 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                cmd = NL80211_CMD_SET_BEACON;
 
        nl80211_cmd(drv, msg, 0, cmd);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
+                   params->head, params->head_len);
        NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+       wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
+                   params->tail, params->tail_len);
        NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
+       wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
        NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+       wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
        NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+       wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
+                         params->ssid, params->ssid_len);
        NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
                params->ssid);
-       if (params->proberesp && params->proberesp_len)
+       if (params->proberesp && params->proberesp_len) {
+               wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
+                           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:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_NOT_IN_USE);
                break;
        case HIDDEN_SSID_ZERO_LEN:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_ZERO_LEN);
                break;
        case HIDDEN_SSID_ZERO_CONTENTS:
+               wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
                NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
                            NL80211_HIDDEN_SSID_ZERO_CONTENTS);
                break;
        }
+       wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
        if (params->privacy)
                NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+       wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
        if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
            (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
                /* Leave out the attribute */
@@ -5204,6 +6393,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
                            NL80211_AUTHTYPE_OPEN_SYSTEM);
 
+       wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
        ver = 0;
        if (params->wpa_version & WPA_PROTO_WPA)
                ver |= NL80211_WPA_VERSION_1;
@@ -5212,6 +6402,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        if (ver)
                NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
 
+       wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+                  params->key_mgmt_suites);
        num_suites = 0;
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
                suites[num_suites++] = WLAN_AKM_SUITE_8021X;
@@ -5226,9 +6418,13 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
                NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
 
+       wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+                  params->pairwise_ciphers);
        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)
@@ -5240,11 +6436,17 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        num_suites * sizeof(u32), suites);
        }
 
+       wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+                  params->group_cipher);
        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);
@@ -5260,20 +6462,33 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        }
 
        if (params->beacon_ies) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
+                               params->beacon_ies);
                NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
                        wpabuf_head(params->beacon_ies));
        }
        if (params->proberesp_ies) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
+                               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) {
+               wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
+                               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)  {
+               wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
+                          params->ap_max_inactivity);
+               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)",
@@ -5284,6 +6499,11 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                                params->short_slot_time, params->ht_opmode,
                                params->isolate, params->basic_rates);
        }
+
+#ifdef TIZEN_EXT
+       wpa_driver_nl80211_probe_req_report(priv, 1);
+#endif
+
        return ret;
  nla_put_failure:
        nlmsg_free(msg);
@@ -5292,16 +6512,16 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-                                      int freq, int ht_enabled,
-                                      int sec_channel_offset)
+                                      struct hostapd_freq_params *freq)
 {
        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);
+       wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
+                  " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+                  freq->freq, freq->ht_enabled, freq->vht_enabled,
+                  freq->bandwidth, freq->center_freq1, freq->center_freq2);
        msg = nlmsg_alloc();
        if (!msg)
                return -1;
@@ -5309,9 +6529,38 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
        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) {
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+       if (freq->vht_enabled) {
+               switch (freq->bandwidth) {
+               case 20:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_20);
+                       break;
+               case 40:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_40);
+                       break;
+               case 80:
+                       if (freq->center_freq2)
+                               NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                           NL80211_CHAN_WIDTH_80P80);
+                       else
+                               NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                           NL80211_CHAN_WIDTH_80);
+                       break;
+               case 160:
+                       NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+                                   NL80211_CHAN_WIDTH_160);
+                       break;
+               default:
+                       return -1;
+               }
+               NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
+               if (freq->center_freq2)
+                       NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
+                                   freq->center_freq2);
+       } else if (freq->ht_enabled) {
+               switch (freq->sec_channel_offset) {
                case -1:
                        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
                                    NL80211_CHAN_HT40MINUS);
@@ -5330,11 +6579,11 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret == 0) {
-               bss->freq = freq;
+               bss->freq = freq->freq;
                return 0;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
-                  "%d (%s)", freq, ret, strerror(-ret));
+                  "%d (%s)", freq->freq, ret, strerror(-ret));
 nla_put_failure:
        nlmsg_free(msg);
        return -1;
@@ -5365,7 +6614,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *wme = NULL;
+       struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
@@ -5377,6 +6626,8 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (!msg)
                return -ENOMEM;
 
+       wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
+                  params->set ? "Set" : "Add", MAC2STR(params->addr));
        nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
                    NL80211_CMD_NEW_STATION);
 
@@ -5384,33 +6635,77 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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);
+       wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
+                   params->supp_rates_len);
        if (!params->set) {
-               NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               if (params->aid) {
+                       wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               } else {
+                       /*
+                        * cfg80211 validates that AID is non-zero, so we have
+                        * to make this a non-zero value for the TDLS case where
+                        * a dummy STA entry is used for now.
+                        */
+                       wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+               }
+               wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
+                          params->listen_interval);
                NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
                            params->listen_interval);
+       } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+               wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
+               NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
        }
        if (params->ht_capabilities) {
+               wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
+                           (u8 *) params->ht_capabilities,
+                           sizeof(*params->ht_capabilities));
                NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
                        sizeof(*params->ht_capabilities),
                        params->ht_capabilities);
        }
 
+       if (params->vht_capabilities) {
+               wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
+                           (u8 *) params->vht_capabilities,
+                           sizeof(*params->vht_capabilities));
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
+                       sizeof(*params->vht_capabilities),
+                       params->vht_capabilities);
+       }
+
+       wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
+       NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+
+       if (params->ext_capab) {
+               wpa_hexdump(MSG_DEBUG, "  * ext_capab",
+                           params->ext_capab, params->ext_capab_len);
+               NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+                       params->ext_capab_len, params->ext_capab);
+       }
+
        os_memset(&upd, 0, sizeof(upd));
        upd.mask = sta_flags_nl80211(params->flags);
        upd.set = upd.mask;
+       wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
+                  upd.set, upd.mask);
        NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
        if (params->flags & WPA_STA_WMM) {
-               wme = nlmsg_alloc();
+               struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
                if (!wme)
                        goto nla_put_failure;
 
-               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+               wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
+               NLA_PUT_U8(msg, 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) &
+               NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
+                               (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
                                WMM_QOSINFO_STA_SP_MASK);
-               nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+               nla_nest_end(msg, wme);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -5422,15 +6717,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
@@ -5490,12 +6783,20 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
                return "STATION";
        case NL80211_IFTYPE_AP:
                return "AP";
+       case NL80211_IFTYPE_AP_VLAN:
+               return "AP_VLAN";
+       case NL80211_IFTYPE_WDS:
+               return "WDS";
        case NL80211_IFTYPE_MONITOR:
                return "MONITOR";
+       case NL80211_IFTYPE_MESH_POINT:
+               return "MESH_POINT";
        case NL80211_IFTYPE_P2P_CLIENT:
                return "P2P_CLIENT";
        case NL80211_IFTYPE_P2P_GO:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -5505,9 +6806,11 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
-                                    const u8 *addr, int wds)
+                                    const u8 *addr, int wds,
+                                    int (*handler)(struct nl_msg *, void *),
+                                    void *arg)
 {
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
        int ifidx;
        int ret = -ENOBUFS;
 
@@ -5519,30 +6822,26 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return -1;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
        if (iftype == NL80211_IFTYPE_MONITOR) {
-               int err;
+               struct nlattr *flags;
 
-               flags = nlmsg_alloc();
+               flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
                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);
+               NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-               nlmsg_free(flags);
-
-               if (err)
-                       goto nla_put_failure;
+               nla_nest_end(msg, flags);
        } else if (wds) {
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, handler, arg);
        msg = NULL;
        if (ret) {
  nla_put_failure:
@@ -5552,6 +6851,9 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -5574,11 +6876,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
-                               const u8 *addr, int wds)
+                               const u8 *addr, int wds,
+                               int (*handler)(struct nl_msg *, void *),
+                               void *arg)
 {
        int ret;
 
-       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+                                       arg);
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -5589,10 +6894,10 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
                /* Try to create the interface again */
                ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-                                               wds);
+                                               wds, handler, arg);
        }
 
-       if (ret >= 0 && is_p2p_interface(iftype))
+       if (ret >= 0 && is_p2p_net_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -5721,8 +7026,8 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                case IEEE80211_RADIOTAP_RATE:
                        datarate = *iter.this_arg * 5;
                        break;
-               case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
-                       ssi_signal = *iter.this_arg;
+               case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+                       ssi_signal = (s8) *iter.this_arg;
                        break;
                }
        }
@@ -5939,7 +7244,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -6004,6 +7309,9 @@ 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
@@ -6016,6 +7324,10 @@ static int nl80211_setup_ap(struct i802_bss *bss)
                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)
@@ -6036,12 +7348,14 @@ static void nl80211_teardown_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
-       if (drv->device_ap_sme)
+       if (drv->device_ap_sme) {
                wpa_driver_nl80211_probe_req_report(bss, 0);
-       else if (drv->use_monitor)
+               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);
+               nl80211_mgmt_unsubscribe(bss, "AP teardown");
 
        bss->beacon_set = 0;
 }
@@ -6117,8 +7431,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        pos = (u8 *) (hdr + 1);
 
        if (qos) {
-               /* add an empty QoS header if needed */
-               pos[0] = 0;
+               /* Set highest priority in QoS header */
+               pos[0] = 7;
                pos[1] = 0;
                pos += 2;
        }
@@ -6129,7 +7443,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        pos += 2;
        memcpy(pos, data, data_len);
 
-       res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0);
+       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)",
@@ -6147,19 +7462,14 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
+       struct nlattr *flags;
        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,
@@ -6170,35 +7480,34 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
         * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
         * can be removed eventually.
         */
+       flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+       if (!flags)
+               goto nla_put_failure;
        if (total_flags & WPA_STA_AUTHORIZED)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
        if (total_flags & WPA_STA_WMM)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
        if (total_flags & WPA_STA_SHORT_PREAMBLE)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
        if (total_flags & WPA_STA_MFP)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
        if (total_flags & WPA_STA_TDLS_PEER)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-       if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-               goto nla_put_failure;
+       nla_nest_end(msg, flags);
 
        os_memset(&upd, 0, sizeof(upd));
        upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
        upd.set = sta_flags_nl80211(flags_or);
        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;
 }
 
@@ -6206,17 +7515,30 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                                 struct wpa_driver_associate_params *params)
 {
-       enum nl80211_iftype nlmode;
+       enum nl80211_iftype nlmode, old_mode;
+       struct hostapd_freq_params freq = {
+               .freq = params->freq,
+       };
 
+#ifdef TIZEN_EXT
+       nlmode = NL80211_IFTYPE_AP;
+#else
        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;
+#endif
+       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_mode(&drv->first_bss, nlmode) ||
-           wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
+       if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+               if (old_mode != nlmode)
+                       wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
                nl80211_remove_monitor_interface(drv);
                return -1;
        }
@@ -6294,6 +7616,20 @@ retry:
        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",
@@ -6327,56 +7663,7 @@ nla_put_failure:
 }
 
 
-static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
-                                           u8 *bssid)
-{
-       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) {
-               if (is_zero_ether_addr(arg.assoc_bssid))
-                       return -ENOTCONN;
-               os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
-               return 0;
-       }
-       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 int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                             const u8 *bssid)
-{
-       u8 addr[ETH_ALEN];
-
-       if (bssid == NULL) {
-               int res = nl80211_get_assoc_bssid(drv, addr);
-               if (res)
-                       return res;
-               bssid = addr;
-       }
-
-       return wpa_driver_nl80211_disconnect(drv, bssid,
-                                            WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static int wpa_driver_nl80211_connect(
+static int wpa_driver_nl80211_try_connect(
        struct wpa_driver_nl80211_data *drv,
        struct wpa_driver_associate_params *params)
 {
@@ -6402,6 +7689,12 @@ static int wpa_driver_nl80211_connect(
                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);
@@ -6445,6 +7738,15 @@ static int wpa_driver_nl80211_connect(
        NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
 
 skip_auth_type:
+#ifdef TIZEN_EXT
+       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;
+#else
        if (params->wpa_proto) {
                enum nl80211_wpa_versions ver = 0;
 
@@ -6452,7 +7754,7 @@ skip_auth_type:
                        ver |= NL80211_WPA_VERSION_1;
                if (params->wpa_proto & WPA_PROTO_RSN)
                        ver |= NL80211_WPA_VERSION_2;
-
+#endif
                wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
                NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
        }
@@ -6461,6 +7763,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->pairwise_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6470,6 +7775,9 @@ skip_auth_type:
                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;
@@ -6482,6 +7790,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->group_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6491,6 +7802,9 @@ skip_auth_type:
                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;
@@ -6500,13 +7814,25 @@ skip_auth_type:
        }
 
        if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-           params->key_mgmt_suite == KEY_MGMT_PSK) {
+           params->key_mgmt_suite == KEY_MGMT_PSK ||
+           params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
+           params->key_mgmt_suite == KEY_MGMT_FT_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_FT_802_1X:
+                       mgmt = WLAN_AKM_SUITE_FT_8021X;
+                       break;
+               case KEY_MGMT_FT_PSK:
+                       mgmt = WLAN_AKM_SUITE_FT_PSK;
+                       break;
                case KEY_MGMT_PSK:
                default:
                        mgmt = WLAN_AKM_SUITE_PSK;
@@ -6515,6 +7841,35 @@ skip_auth_type:
                NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
        }
 
+#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 */
+
+       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);
+       }
+
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                       params->vhtcaps_mask);
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        ret = nl80211_set_conn_keys(params, msg);
        if (ret)
                goto nla_put_failure;
@@ -6524,14 +7879,6 @@ skip_auth_type:
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-               /*
-                * cfg80211 does not currently accept new connection if we are
-                * already connected. As a workaround, force disconnection and
-                * try again once the driver indicates it completed
-                * disconnection.
-                */
-               if (ret == -EALREADY)
-                       nl80211_disconnect(drv, params->bssid);
                goto nla_put_failure;
        }
        ret = 0;
@@ -6544,6 +7891,31 @@ nla_put_failure:
 }
 
 
+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)
 {
@@ -6567,7 +7939,7 @@ static int wpa_driver_nl80211_associate(
                return wpa_driver_nl80211_connect(drv, params);
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -6589,6 +7961,12 @@ static int wpa_driver_nl80211_associate(
                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);
@@ -6617,6 +7995,9 @@ static int wpa_driver_nl80211_associate(
                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;
@@ -6639,6 +8020,9 @@ static int wpa_driver_nl80211_associate(
                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;
@@ -6662,6 +8046,30 @@ static int wpa_driver_nl80211_associate(
                        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);
+       }
+
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+               NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                       params->vhtcaps_mask);
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        if (params->p2p)
                wpa_printf(MSG_DEBUG, "  * P2P group");
 
@@ -6698,7 +8106,8 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
                return -ENOMEM;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6723,6 +8132,9 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        int res;
 
        res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+       if (res && nlmode == nl80211_get_ifmode(bss))
+               res = 0;
+
        if (res == 0) {
                drv->nlmode = nlmode;
                ret = 0;
@@ -6746,8 +8158,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        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);
+               res = i802_set_iface_flags(bss, 0);
                if (res == -EACCES || res == -ENODEV)
                        break;
                if (res == 0) {
@@ -6756,8 +8167,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                        ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
                        if (ret == -EACCES)
                                break;
-                       res = linux_set_iface_flags(drv->global->ioctl_sock,
-                                                   bss->ifname, 1);
+                       res = i802_set_iface_flags(bss, 1);
                        if (res && !ret)
                                ret = -1;
                        else if (ret != -EBUSY)
@@ -6782,8 +8192,13 @@ done:
                return ret;
        }
 
+       if (is_p2p_net_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);
+               nl80211_mgmt_unsubscribe(bss, "start AP");
                /* Setup additional AP mode functionality if needed */
                if (nl80211_setup_ap(bss))
                        return -1;
@@ -6791,10 +8206,10 @@ done:
                /* Remove additional AP mode functionality */
                nl80211_teardown_ap(bss);
        } else {
-               nl80211_mgmt_unsubscribe(bss);
+               nl80211_mgmt_unsubscribe(bss, "mode change");
        }
 
-       if (!is_ap_interface(nlmode) &&
+       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");
@@ -6811,6 +8226,18 @@ static int wpa_driver_nl80211_get_capa(void *priv,
        if (!drv->has_capability)
                return -1;
        os_memcpy(capa, &drv->capa, sizeof(*capa));
+       if (drv->extended_capa && drv->extended_capa_mask) {
+               capa->extended_capa = drv->extended_capa;
+               capa->extended_capa_mask = drv->extended_capa_mask;
+               capa->extended_capa_len = drv->extended_capa_len;
+       }
+
+       if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           !drv->allow_p2p_device) {
+               wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+               capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+       }
+
        return 0;
 }
 
@@ -6835,6 +8262,9 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
        struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+                  MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
@@ -6862,8 +8292,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 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);
+       return wpa_driver_nl80211_set_freq(bss, freq);
 }
 
 
@@ -6996,6 +8425,7 @@ 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)
@@ -7009,12 +8439,19 @@ static int i802_flush(void *priv)
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
                    if_nametoindex(bss->ifname));
 
-       return send_and_recv_msgs(drv, msg, NULL, NULL);
+       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)
 {
@@ -7028,6 +8465,7 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                [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),
@@ -7063,14 +8501,17 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
        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,
+static int i802_read_sta_data(struct i802_bss *bss,
+                             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;
 
@@ -7091,6 +8532,8 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
 }
 
 
+#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)
 {
@@ -7150,10 +8593,9 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 }
 
 
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
+static int i802_set_sta_vlan(struct i802_bss *bss, 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;
@@ -7210,8 +8652,12 @@ 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);
@@ -7221,7 +8667,8 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        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);
+                                           sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+                                           0);
 }
 
 
@@ -7229,8 +8676,12 @@ 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);
@@ -7240,7 +8691,8 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        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);
+                                           sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+                                           0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -7266,8 +8718,8 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
        else
                old = NULL;
 
-       drv->if_indices = os_realloc(old,
-                                    sizeof(int) * (drv->num_if_indices + 1));
+       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;
@@ -7324,16 +8776,23 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                NULL, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
                                            bridge_ifname, name) < 0)
                                return -1;
                }
-               linux_set_iface_flags(drv->global->ioctl_sock, name, 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);
@@ -7511,7 +8970,8 @@ failed:
 
 static void i802_deinit(void *priv)
 {
-       wpa_driver_nl80211_deinit(priv);
+       struct i802_bss *bss = priv;
+       wpa_driver_nl80211_deinit(bss);
 }
 
 #endif /* HOSTAPD */
@@ -7525,13 +8985,23 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_STATION;
        case WPA_IF_P2P_CLIENT:
        case WPA_IF_P2P_GROUP:
+#ifdef TIZEN_EXT
+               return NL80211_IFTYPE_STATION;
+#else
                return NL80211_IFTYPE_P2P_CLIENT;
+#endif
        case WPA_IF_AP_VLAN:
                return NL80211_IFTYPE_AP_VLAN;
        case WPA_IF_AP_BSS:
                return NL80211_IFTYPE_AP;
        case WPA_IF_P2P_GO:
+#ifdef TIZEN_EXT
+               return NL80211_IFTYPE_AP;
+#else
                return NL80211_IFTYPE_P2P_GO;
+#endif
+       case WPA_IF_P2P_DEVICE:
+               return NL80211_IFTYPE_P2P_DEVICE;
        }
        return -1;
 }
@@ -7578,12 +9048,40 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
 #endif /* CONFIG_P2P */
 
 
+struct wdev_info {
+       u64 wdev_id;
+       int wdev_id_set;
+       u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct wdev_info *wi = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (tb[NL80211_ATTR_WDEV]) {
+               wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wi->wdev_id_set = 1;
+       }
+
+       if (tb[NL80211_ATTR_MAC])
+               os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
+       return NL_SKIP;
+}
+
+
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
                                     void *bss_ctx, void **drv_priv,
                                     char *force_ifname, u8 *if_addr,
                                     const char *bridge)
 {
+       enum nl80211_iftype nlmode;
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifidx;
@@ -7599,21 +9097,46 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 
        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) {
+       nlmode = wpa_driver_nl80211_if_type(type);
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               struct wdev_info p2pdev_info;
+
+               os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, nl80211_wdev_handler,
+                                            &p2pdev_info);
+               if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+                                  ifname);
+                       return -1;
+               }
+
+               drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+               drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+               if (!is_zero_ether_addr(p2pdev_info.macaddr))
+                       os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+               wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+                          ifname,
+                          (long long unsigned int) p2pdev_info.wdev_id);
+       } else {
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, NULL, NULL);
+               if (ifidx < 0) {
 #ifdef HOSTAPD
-               os_free(new_bss);
+                       os_free(new_bss);
 #endif /* HOSTAPD */
-               return -1;
+                       return -1;
+               }
        }
 
-       if (!addr &&
-           linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              if_addr) < 0) {
-               nl80211_remove_iface(drv, ifidx);
-               return -1;
+       if (!addr) {
+               if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+                       os_memcpy(if_addr, bss->addr, ETH_ALEN);
+               else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+                                           bss->ifname, if_addr) < 0) {
+                       nl80211_remove_iface(drv, ifidx);
+                       return -1;
+               }
        }
 
 #ifdef CONFIG_P2P
@@ -7621,16 +9144,14 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
            (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];
+               u8 new_addr[ETH_ALEN];
 
-               if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      own_addr) < 0 ||
-                   linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+               if (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) {
+               if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
                                   "for P2P group interface");
                        if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
@@ -7669,10 +9190,16 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                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 */
 
@@ -7683,11 +9210,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 }
 
 
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                        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);
 
@@ -7696,7 +9222,12 @@ static int wpa_driver_nl80211_if_remove(void *priv,
        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)
@@ -7710,13 +9241,6 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                                   "bridge %s: %s",
                                   bss->brname, strerror(errno));
        }
-#endif /* HOSTAPD */
-
-       nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
-       if (type != WPA_IF_AP_BSS)
-               return 0;
 
        if (bss != &drv->first_bss) {
                struct i802_bss *tbss;
@@ -7724,6 +9248,8 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                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;
@@ -7768,13 +9294,20 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
        if (!msg)
                return -1;
 
+       wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+                  "no_ack=%d offchanok=%d",
+                  freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+#ifndef BCM_DRIVER_V115
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
-       if (offchanok)
+#endif
+       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);
@@ -7792,7 +9325,7 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                           freq, wait);
                goto nla_put_failure;
        }
-       wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+       wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
                   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
                   (long long unsigned int) cookie);
 
@@ -7805,21 +9338,22 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+                                         unsigned int freq,
                                          unsigned int wait_time,
                                          const u8 *dst, const u8 *src,
                                          const u8 *bssid,
                                          const u8 *data, size_t data_len,
                                          int no_cck)
 {
-       struct 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, "
-                  "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
+                  "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)
@@ -7833,8 +9367,9 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
        if (is_ap_interface(drv->nlmode))
-               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
-                                                  0);
+               ret = wpa_driver_nl80211_send_mlme(bss, 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,
@@ -7857,9 +9392,12 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
        if (!msg)
                return;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
+                  (long long unsigned int) drv->send_action_cookie);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7888,7 +9426,9 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -7935,7 +9475,9 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7950,13 +9492,23 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
        if (!report) {
-               if (bss->nl_preq) {
+               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);
@@ -7966,20 +9518,61 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 
        if (bss->nl_preq) {
                wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
-                          "already on!");
+                          "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;
+
+#ifdef TIZEN_EXT
+       if (drv->nlmode != NL80211_IFTYPE_AP &&
+               drv->nlmode != NL80211_IFTYPE_P2P_GO) {
+               wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
+                          "allowed in AP or P2P GO mode (iftype=%d)",
+                          drv->nlmode);
+               goto done;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                          (WLAN_FC_TYPE_MGMT << 2) |
+                          (WLAN_FC_STYPE_ASSOC_REQ << 4),
+                          NULL, 0) < 0) {
+               goto out_err;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                          (WLAN_FC_TYPE_MGMT << 2) |
+                          (WLAN_FC_STYPE_REASSOC_REQ << 4),
+                          NULL, 0) < 0) {
+               goto out_err;
+       }
+
+       if (nl80211_register_frame(bss, bss->nl_preq,
+                          (WLAN_FC_TYPE_MGMT << 2) |
+                          (WLAN_FC_STYPE_DISASSOC << 4),
+                          NULL, 0) < 0) {
+               goto out_err;
+       }
 
        if (nl80211_register_frame(bss, bss->nl_preq,
-                                  (WLAN_FC_TYPE_MGMT << 2) |
-                                  (WLAN_FC_STYPE_PROBE_REQ << 4),
-                                  NULL, 0) < 0)
+                                          (WLAN_FC_TYPE_MGMT << 2) |
+                                          (WLAN_FC_STYPE_DEAUTH << 4),
+                                          NULL, 0) < 0) {
                goto out_err;
+       }
 
+done:
+#endif
        eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
                                 wpa_driver_nl80211_event_receive, bss->nl_cb,
                                 bss->nl_preq);
@@ -8031,7 +9624,8 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        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;
 
@@ -8052,14 +9646,34 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
 }
 
 
-static void wpa_driver_nl80211_resume(void *priv)
+static int wpa_driver_nl80211_stop_ap(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");
-       }
+       if (!is_ap_interface(drv->nlmode))
+               return -1;
+       wpa_driver_nl80211_del_beacon(drv);
+       bss->beacon_set = 0;
+       return 0;
+}
+
+
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
+               return -1;
+       return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
+static void wpa_driver_nl80211_resume(void *priv)
+{
+       struct i802_bss *bss = priv;
+
+       if (i802_set_iface_flags(bss, 1))
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
 }
 
 
@@ -8114,7 +9728,9 @@ 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;
+       struct nl_msg *msg;
+       struct nlattr *cqm;
+       int ret = -1;
 
        wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
                   "hysteresis=%d", threshold, hysteresis);
@@ -8127,22 +9743,89 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-       cqm = nlmsg_alloc();
+       cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
        if (cqm == NULL)
-               return -1;
+               goto nla_put_failure;
 
-       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);
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+       nla_nest_end(msg, cqm);
 
-       if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-               return 0;
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
 
 nla_put_failure:
-       nlmsg_free(cqm);
        nlmsg_free(msg);
-       return -1;
+       return ret;
+}
+
+
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+       switch (width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return CHAN_WIDTH_20_NOHT;
+       case NL80211_CHAN_WIDTH_20:
+               return CHAN_WIDTH_20;
+       case NL80211_CHAN_WIDTH_40:
+               return CHAN_WIDTH_40;
+       case NL80211_CHAN_WIDTH_80:
+               return CHAN_WIDTH_80;
+       case NL80211_CHAN_WIDTH_80P80:
+               return CHAN_WIDTH_80P80;
+       case NL80211_CHAN_WIDTH_160:
+               return CHAN_WIDTH_160;
+       }
+       return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       sig_change->center_frq1 = -1;
+       sig_change->center_frq2 = -1;
+       sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+               sig_change->chanwidth = convert2width(
+                       nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+               if (tb[NL80211_ATTR_CENTER_FREQ1])
+                       sig_change->center_frq1 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+               if (tb[NL80211_ATTR_CENTER_FREQ2])
+                       sig_change->center_frq2 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_signal_info *sig)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
 }
 
 
@@ -8157,6 +9840,10 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
        if (res != 0)
                return res;
 
+       res = nl80211_get_channel_width(drv, si);
+       if (res != 0)
+               return res;
+
        return nl80211_get_link_noise(drv, si);
 }
 
@@ -8186,7 +9873,10 @@ static int wpa_driver_nl80211_shared_freq(void *priv)
                           MACSTR,
                           driver->phyname, driver->first_bss.ifname,
                           MAC2STR(driver->first_bss.addr));
-               freq = nl80211_get_assoc_freq(driver);
+               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);
        }
@@ -8203,7 +9893,8 @@ 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);
+       return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
+                                            0, 0, 0, 0);
 }
 
 
@@ -8222,6 +9913,17 @@ static int nl80211_set_param(void *priv, const char *param)
                           "interface");
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+
+#if defined(TIZEN_EXT_P2P) && defined(BCM_DRIVER_V115)
+               wpa_printf(MSG_ERROR, "nl80211: Use Multi channel concurrency");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+#endif /* TIZEN_EXT_P2P && BCM_DRIVER_V115 */
+       }
+
+       if (os_strstr(param, "p2p_device=1")) {
+               struct i802_bss *bss = priv;
+               struct wpa_driver_nl80211_data *drv = bss->drv;
+               drv->allow_p2p_device = 1;
        }
 #endif /* CONFIG_P2P */
 
@@ -8425,7 +10127,8 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
        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)
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+                                        0, 0) < 0)
                wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
                           "send poll frame");
 }
@@ -8497,6 +10200,40 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
 }
 
 
+static int nl80211_start_radar_detection(void *priv, int freq)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+                          "detection");
+               return -1;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+       /* only HT20 is supported at this point */
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret == 0)
+               return 0;
+       wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+                  "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+       return -1;
+}
+
 #ifdef CONFIG_TDLS
 
 static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -8719,35 +10456,291 @@ static int android_pno_stop(struct i802_bss *bss)
 #endif /* ANDROID */
 
 
+static int 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;
+       return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
+                                         set_tx, seq, seq_len, key, key_len);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+                               struct wpa_driver_scan_params *params)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+                                        int reason_code)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+                                      struct wpa_driver_auth_params *params)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+       struct i802_bss *bss = priv;
+       wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+                                   const char *ifname)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+                                   size_t data_len, int noack)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+                                           0, 0, 0, 0);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_sta_remove(bss, addr);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+                                      const char *ifname, int vlan_id)
+{
+       struct i802_bss *bss = priv;
+       return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+                                       struct hostap_sta_driver_data *data,
+                                       const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+                                     unsigned int wait_time,
+                                     const u8 *dst, const u8 *src,
+                                     const u8 *bssid,
+                                     const u8 *data, size_t data_len,
+                                     int no_cck)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+                                             bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+       struct i802_bss *bss = priv;
+       return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
+static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
+                                           const u8 *ies, size_t ies_len)
+{
+       int ret;
+       struct nl_msg *msg;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       u16 mdid = WPA_GET_LE16(md);
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+       NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
+                          "err=%d (%s)", ret, strerror(-ret));
+       }
+
+       return ret;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+               return NULL;
+
+       return bss->addr;
+}
+
+#if defined(TIZEN_EXT_P2P) && defined(BCM_DRIVER_V115)
+
+#define MAX_WPSP2PIE_CMD_SIZE          384
+
+typedef struct tizen_wifi_priv_cmd {
+       char *buf;
+       int used_len;
+       int total_len;
+} bcm_driver_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 > 4) {
+               drv_errors = 0;
+               wpa_msg(drv->ctx, MSG_INFO, "BCM Driver State : HANGED");
+       }
+}
+
+int wpa_driver_nl80211_priv_cmd_bcm(void *priv, char *cmd, char *buf,
+                                 size_t buf_len )
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       bcm_driver_priv_cmd priv_cmd_data;
+       int ret = 0;
+
+       if (cmd)
+               wpa_printf(MSG_DEBUG, "%s = %s", __func__, cmd);
+
+       os_memcpy(buf, cmd, strlen(cmd) + 1);
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&priv_cmd_data, 0, sizeof(priv_cmd_data));
+       os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       priv_cmd_data.buf = buf;
+       priv_cmd_data.used_len = buf_len;
+       priv_cmd_data.total_len = buf_len;
+       ifr.ifr_data = &priv_cmd_data;
+
+       wpa_printf(MSG_DEBUG, "[KGB_DEBUG] %s: ioctl socket [%d], ifname [%s]", __func__, drv->global->ioctl_sock, bss->ifname);
+       errno = 0;
+       if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
+               wpa_printf(MSG_ERROR, "%s: failed to issue private commands. Error [%s]", __func__, strerror(errno));
+               wpa_driver_send_hang_msg(drv);
+       } else {
+               drv_errors = 0;
+               ret = 0;
+               if ((os_strcasecmp(cmd, "LINKSPEED") == 0) ||
+                   (os_strcasecmp(cmd, "RSSI") == 0) ||
+                   (os_strcasecmp(cmd, "GETBAND") == 0) ||
+                   (os_strcasecmp(cmd, "P2P_GET_NOA") == 0))
+                       ret = strlen(buf);
+
+               wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
+       }
+       return ret;
+}
+
+int wpa_driver_nl80211_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+                                const struct wpabuf *proberesp,
+                                const struct wpabuf *assocresp)
+{
+       char buf[MAX_WPSP2PIE_CMD_SIZE+768];
+       struct wpabuf *ap_wps_p2p_ie = NULL;
+       char *_cmd = "SET_AP_WPS_P2P_IE";
+       char *pbuf;
+       int ret = 0;
+       int i;
+       struct cmd_desc {
+               int cmd;
+               const struct wpabuf *src;
+       } cmd_arr[] = {
+               {0x1, beacon},
+               {0x2, proberesp},
+               {0x4, assocresp},
+               {-1, NULL}
+       };
+
+       wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+       for (i = 0; cmd_arr[i].cmd != -1; i++) {
+               os_memset(buf, 0, sizeof(buf));
+               pbuf = buf;
+               pbuf += sprintf(pbuf, "%s %d", _cmd, cmd_arr[i].cmd);
+               *pbuf++ = '\0';
+               ap_wps_p2p_ie = cmd_arr[i].src ?
+                       wpabuf_dup(cmd_arr[i].src) : NULL;
+               if (ap_wps_p2p_ie) {
+                       os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie));
+                       ret = wpa_driver_nl80211_priv_cmd_bcm(priv, buf, buf,
+                               strlen(_cmd) + 3 + wpabuf_len(ap_wps_p2p_ie));
+                       wpabuf_free(ap_wps_p2p_ie);
+                       if (ret < 0)
+                               break;
+               }
+       }
+
+       return ret;
+}
+#endif /* TIZEN_EXT_P2P && BCM_DRIVER_V115*/
+
+
 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,
+       .set_key = driver_nl80211_set_key,
+       .scan2 = driver_nl80211_scan2,
        .sched_scan = wpa_driver_nl80211_sched_scan,
        .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
        .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
-       .deauthenticate = wpa_driver_nl80211_deauthenticate,
-       .disassociate = wpa_driver_nl80211_disassociate,
-       .authenticate = wpa_driver_nl80211_authenticate,
+       .deauthenticate = driver_nl80211_deauthenticate,
+       .authenticate = driver_nl80211_authenticate,
        .associate = wpa_driver_nl80211_associate,
        .global_init = nl80211_global_init,
        .global_deinit = nl80211_global_deinit,
        .init2 = wpa_driver_nl80211_init,
-       .deinit = wpa_driver_nl80211_deinit,
+       .deinit = driver_nl80211_deinit,
        .get_capa = wpa_driver_nl80211_get_capa,
        .set_operstate = wpa_driver_nl80211_set_operstate,
        .set_supp_port = wpa_driver_nl80211_set_supp_port,
        .set_country = wpa_driver_nl80211_set_country,
        .set_ap = wpa_driver_nl80211_set_ap,
+       .set_acl = wpa_driver_nl80211_set_acl,
        .if_add = wpa_driver_nl80211_if_add,
-       .if_remove = wpa_driver_nl80211_if_remove,
-       .send_mlme = wpa_driver_nl80211_send_mlme,
+       .if_remove = driver_nl80211_if_remove,
+       .send_mlme = 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,
+       .sta_remove = driver_nl80211_sta_remove,
        .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
        .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
 #ifdef HOSTAPD
@@ -8758,24 +10751,25 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #if defined(HOSTAPD) || defined(CONFIG_AP)
        .get_seqnum = i802_get_seqnum,
        .flush = i802_flush,
-       .read_sta_data = i802_read_sta_data,
        .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,
+       .set_sta_vlan = driver_nl80211_set_sta_vlan,
        .sta_deauth = i802_sta_deauth,
        .sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
+       .read_sta_data = driver_nl80211_read_sta_data,
        .set_freq = i802_set_freq,
-       .send_action = wpa_driver_nl80211_send_action,
+       .send_action = driver_nl80211_send_action,
        .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
        .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
        .cancel_remain_on_channel =
        wpa_driver_nl80211_cancel_remain_on_channel,
-       .probe_req_report = wpa_driver_nl80211_probe_req_report,
+       .probe_req_report = driver_nl80211_probe_req_report,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
+       .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
        .resume = wpa_driver_nl80211_resume,
        .send_ft_action = nl80211_send_ft_action,
        .signal_monitor = nl80211_signal_monitor,
@@ -8790,8 +10784,16 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_rekey_info = nl80211_set_rekey_info,
        .poll_client = nl80211_poll_client,
        .set_p2p_powersave = nl80211_set_p2p_powersave,
+       .start_dfs_cac = nl80211_start_radar_detection,
+       .stop_ap = wpa_driver_nl80211_stop_ap,
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
+       .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+       .get_mac_addr = wpa_driver_nl80211_get_macaddr,
+#if defined(TIZEN_EXT_P2P) && defined(BCM_DRIVER_V115)
+       .priv_cmd = wpa_driver_nl80211_priv_cmd_bcm,
+       .set_ap_wps_ie = wpa_driver_nl80211_set_ap_wps_p2p_ie,
+#endif /* TIZEN_EXT_P2P && BCM_DRIVER_V115 */
 };
index aaeacd6..d75c14b 100644 (file)
@@ -2,14 +2,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
new file mode 100644 (file)
index 0000000..e94eda0
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Driver interaction with OpenBSD net80211 layer
+ * Copyright (c) 2013, Mark Kettenis
+ *
+ * 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>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+
+struct openbsd_driver_data {
+       char ifname[IFNAMSIZ + 1];
+       void *ctx;
+
+       int sock;                       /* open socket for 802.11 ioctls */
+};
+
+
+static int
+wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
+{
+       struct openbsd_driver_data *drv = priv;
+       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;
+}
+
+static int
+wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
+{
+       struct openbsd_driver_data *drv = priv;
+       struct ieee80211_bssid id;
+
+       os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
+       if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
+               return -1;
+
+       os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
+       return 0;
+}
+
+
+static int
+wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+       os_memset(capa, 0, sizeof(*capa));
+       capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+       return 0;
+}
+
+
+static int
+wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+           const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+           size_t seq_len, const u8 *key, size_t key_len)
+{
+       struct openbsd_driver_data *drv = priv;
+       struct ieee80211_keyavail keyavail;
+
+       if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+               return -1;
+
+       memset(&keyavail, 0, sizeof(keyavail));
+       os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
+       if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
+               return -1;
+       memcpy(keyavail.i_key, key, key_len);
+
+       if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
+               return -1;
+
+       return 0;
+}
+
+static void *
+wpa_driver_openbsd_init(void *ctx, const char *ifname)
+{
+       struct openbsd_driver_data *drv;
+
+       drv = os_zalloc(sizeof(*drv));
+       if (drv == NULL)
+               return NULL;
+
+       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+       if (drv->sock < 0)
+               goto fail;
+
+       drv->ctx = ctx;
+       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+       return drv;
+
+fail:
+       os_free(drv);
+       return NULL;
+}
+
+
+static void
+wpa_driver_openbsd_deinit(void *priv)
+{
+       struct openbsd_driver_data *drv = priv;
+
+       close(drv->sock);
+       os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_openbsd_ops = {
+       .name = "openbsd",
+       .desc = "OpenBSD 802.11 support",
+       .get_ssid = wpa_driver_openbsd_get_ssid,
+       .get_bssid = wpa_driver_openbsd_get_bssid,
+       .get_capa = wpa_driver_openbsd_get_capa,
+       .set_key = wpa_driver_openbsd_set_key,
+       .init = wpa_driver_openbsd_init,
+       .deinit = wpa_driver_openbsd_deinit,
+};
index 2848521..ed88e71 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - privilege separated driver interface
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -158,7 +152,7 @@ wpa_driver_privsep_get_scan_results2(void *priv)
                return NULL;
        }
 
-       results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+       results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
        if (results->res == NULL) {
                os_free(results);
                os_free(buf);
@@ -310,17 +304,6 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-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)
@@ -657,7 +640,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
        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)");
+               perror("privsep-set-params priv-sock: bind(PF_UNIX)");
                close(drv->priv_socket);
                drv->priv_socket = -1;
                unlink(drv->own_socket_path);
@@ -682,7 +665,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
        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)");
+               perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
                close(drv->cmd_socket);
                drv->cmd_socket = -1;
                unlink(drv->own_cmd_path);
@@ -742,7 +725,6 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
        .set_param = wpa_driver_privsep_set_param,
        .scan2 = wpa_driver_privsep_scan,
        .deauthenticate = wpa_driver_privsep_deauthenticate,
-       .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,
index 61b75b1..0a9078a 100644 (file)
@@ -2,14 +2,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f8e314b..541ebcc 100644 (file)
@@ -2,14 +2,8 @@
  * Testing driver interface for a simulated network driver
  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 */
@@ -1281,7 +1275,7 @@ static void * test_driver_init(struct hostapd_data *hapd,
                        alen = sizeof(addr_un);
                }
                if (bind(drv->test_socket, addr, alen) < 0) {
-                       perror("bind(PF_UNIX)");
+                       perror("test-driver-init: bind(PF_UNIX)");
                        close(drv->test_socket);
                        if (drv->own_socket_path)
                                unlink(drv->own_socket_path);
@@ -1324,10 +1318,12 @@ static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
        if (drv->pending_p2p_scan && drv->p2p) {
 #ifdef CONFIG_P2P
                size_t i;
+               struct os_time now;
+               os_get_time(&now);
                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->level,
+                                                bss->freq, &now, bss->level,
                                                 (const u8 *) (bss + 1),
                                                 bss->ie_len) > 0)
                                return;
@@ -1484,7 +1480,7 @@ static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
        if (res == NULL)
                return NULL;
 
-       res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+       res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
        if (res->res == NULL) {
                os_free(res);
                return NULL;
@@ -1720,20 +1716,6 @@ static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-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;
@@ -2258,7 +2240,7 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
        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)");
+               perror("test-driver-attach: bind(PF_UNIX)");
                close(drv->test_socket);
                unlink(drv->own_socket_path);
                os_free(drv->own_socket_path);
@@ -2576,15 +2558,14 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 
        *num_modes = 3;
        *flags = 0;
-       modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+       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_zalloc(11 * sizeof(struct hostapd_channel_data));
-       modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
+       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++) {
@@ -2608,9 +2589,8 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        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));
+       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++) {
@@ -2626,8 +2606,8 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        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));
+       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;
@@ -2828,17 +2808,19 @@ static int wpa_driver_test_probe_req_report(void *priv, int report)
 
 static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
 {
-       struct wpa_driver_test_data *drv = priv;
+       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);
+       return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
 }
 
 
 static int wpa_driver_test_p2p_stop_find(void *priv)
 {
-       struct wpa_driver_test_data *drv = 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;
@@ -2849,7 +2831,8 @@ static int wpa_driver_test_p2p_stop_find(void *priv)
 
 static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
 {
-       struct wpa_driver_test_data *drv = priv;
+       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;
@@ -2863,7 +2846,8 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
                                       unsigned int force_freq,
                                       int persistent_group)
 {
-       struct wpa_driver_test_data *drv = priv;
+       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 "
@@ -2873,13 +2857,15 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
        if (!drv->p2p)
                return -1;
        return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
-                          own_interface_addr, force_freq, persistent_group);
+                          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 wpa_driver_test_data *drv = priv;
+       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)
@@ -2891,7 +2877,8 @@ static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
 
 static int wpa_driver_test_p2p_group_formation_failed(void *priv)
 {
-       struct wpa_driver_test_data *drv = 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;
@@ -2903,7 +2890,8 @@ static int wpa_driver_test_p2p_group_formation_failed(void *priv)
 static int wpa_driver_test_p2p_set_params(void *priv,
                                          const struct p2p_params *params)
 {
-       struct wpa_driver_test_data *drv = 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;
@@ -2918,7 +2906,7 @@ static int wpa_driver_test_p2p_set_params(void *priv,
 
 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 *req_dev_types, const u8 *dev_id, u16 pw_id)
 {
        struct wpa_driver_test_data *drv = ctx;
        struct wpa_driver_scan_params params;
@@ -2939,8 +2927,8 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 
 #if 0 /* TODO: WPS IE */
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+       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
@@ -2956,7 +2944,7 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        wpabuf_put_buf(ies, wps_ie);
        wpabuf_free(wps_ie);
 
-       p2p_scan_ie(drv->p2p, ies);
+       p2p_scan_ie(drv->p2p, ies, dev_id);
 
        params.extra_ies = wpabuf_head(ies);
        params.extra_ies_len = wpabuf_len(ies);
@@ -2967,11 +2955,6 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                break;
        case P2P_SCAN_FULL:
                break;
-       case P2P_SCAN_SPECIFIC:
-               social_channels[0] = freq;
-               social_channels[1] = 0;
-               params.freqs = social_channels;
-               break;
        case P2P_SCAN_SOCIAL_PLUS_ONE:
                social_channels[3] = freq;
                params.freqs = social_channels;
@@ -3212,6 +3195,12 @@ static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
        /* TODO */
 }
 
+
+static void test_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+       wpa_printf(level, "P2P: %s", msg);
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -3223,8 +3212,8 @@ static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv)
        int i;
 
        os_memset(&p2p, 0, sizeof(p2p));
-       p2p.msg_ctx = drv->ctx;
        p2p.cb_ctx = drv;
+       p2p.debug_print = test_p2p_debug_print;
        p2p.p2p_scan = test_p2p_scan;
        p2p.send_action = test_send_action;
        p2p.send_action_done = test_send_action_done;
@@ -3304,7 +3293,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .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,
index c11ee75..1401050 100644 (file)
@@ -2,14 +2,8 @@
  * Driver interaction with generic Linux Wireless Extensions
  * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -508,11 +502,9 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                           "IWEVCUSTOM length");
                                return;
                        }
-                       buf = os_malloc(iwe->u.data.length + 1);
+                       buf = dup_binstr(custom, iwe->u.data.length);
                        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;
@@ -575,10 +567,28 @@ static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
                   del ? "removed" : "added");
 
        if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
-               if (del)
+               if (del) {
+                       if (drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+                                          "already set - ignore event");
+                               return;
+                       }
                        drv->if_removed = 1;
-               else
+               } 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);
@@ -634,6 +644,7 @@ static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
        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",
@@ -656,9 +667,25 @@ static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
        }
 
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
-               wpa_printf(MSG_DEBUG, "WEXT: Interface up");
-               drv->if_disabled = 0;
-               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+               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);
+               }
        }
 
        /*
@@ -1385,8 +1412,8 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
        if (data->ie)
                os_memcpy(pos, data->ie, data->ie_len);
 
-       tmp = os_realloc(res->res,
-                        (res->num + 1) * sizeof(struct wpa_scan_res *));
+       tmp = os_realloc_array(res->res, res->num + 1,
+                              sizeof(struct wpa_scan_res *));
        if (tmp == NULL) {
                os_free(r);
                return;
@@ -1546,6 +1573,7 @@ static int wpa_driver_wext_get_range(void *priv)
                }
                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)
@@ -1865,13 +1893,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
                                   "selection on disconnect");
                }
 
-               /*
-                * Oct, 21st. 2011. TIZEN
-                * broadcom driver returns scan abort due to disconnect
-                * Therefore, disconnect operation is blocked by using set_ssid
-                */
-#if defined TIZEN_EXT
-#else
 #ifndef ANDROID
                if (drv->cfg80211) {
                        /*
@@ -1899,7 +1920,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
                                   "SSID to disconnect");
                }
 #endif /* ANDROID */
-#endif
        }
 }
 
@@ -1916,18 +1936,6 @@ static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-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)
 {
@@ -2463,7 +2471,6 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
        .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,
index 8bcbee6..c4a5bc9 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - driver_wext exported functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DRIVER_WEXT_H
index 618db26..e0f0f22 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004, Gunter Burchardt <tira@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 667ea22..04eb4fd 100644 (file)
@@ -2,14 +2,8 @@
  * Driver interface list
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -30,6 +24,9 @@ extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
+#endif /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
 extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
 #endif /* CONFIG_DRIVER_NDIS */
@@ -53,12 +50,12 @@ extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
 
 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_WEXT
+       &wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_HOSTAP
        &wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
@@ -68,6 +65,9 @@ struct wpa_driver_ops *wpa_drivers[] =
 #ifdef CONFIG_DRIVER_BSD
        &wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+       &wpa_driver_openbsd_ops,
+#endif /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
        &wpa_driver_ndis_ops,
 #endif /* CONFIG_DRIVER_NDIS */
index 0cc81f9..68ff910 100644 (file)
@@ -30,7 +30,7 @@ NEED_RFKILL=y
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
 else
   ifdef CONFIG_LIBNL_TINY
     DRV_LIBS += -lnl-tiny
@@ -55,6 +55,14 @@ CONFIG_L2_FREEBSD=y
 CONFIG_DNET_PCAP=y
 endif
 
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += ../src/drivers/driver_openbsd.o
+endif
+
 ifdef CONFIG_DRIVER_TEST
 DRV_CFLAGS += -DCONFIG_DRIVER_TEST
 DRV_OBJS += ../src/drivers/driver_test.o
@@ -142,6 +150,28 @@ 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)
index 1d7129c..db8561a 100644 (file)
@@ -30,7 +30,7 @@ NEED_RFKILL=y
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
 else
   ifdef CONFIG_LIBNL_TINY
     DRV_LIBS += -lnl-tiny
@@ -55,6 +55,14 @@ CONFIG_L2_FREEBSD=y
 CONFIG_DNET_PCAP=y
 endif
 
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += src/drivers/driver_openbsd.c
+endif
+
 ifdef CONFIG_DRIVER_TEST
 DRV_CFLAGS += -DCONFIG_DRIVER_TEST
 DRV_OBJS += src/drivers/driver_test.c
@@ -146,6 +154,29 @@ 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)
index d7501cf..4380428 100644 (file)
@@ -2,14 +2,8 @@
  * Linux ioctl helper functions for driver wrappers
  * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -51,8 +45,9 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
 
        if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
                ret = errno ? -errno : -999;
-               wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
-                          ifname, strerror(errno));
+               wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+                          "%s",
+                          ifname, dev_up ? "UP" : "DOWN", strerror(errno));
                return ret;
        }
 
index e0bf673..c03fe6e 100644 (file)
@@ -2,14 +2,8 @@
  * Linux ioctl helper functions for driver wrappers
  * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef LINUX_IOCTL_H
index b6eea68..55cf955 100644 (file)
@@ -2,14 +2,8 @@
  * Driver interaction with generic Linux Wireless Extensions
  * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef LINUX_WEXT_H
index f6eaa7c..93673a3 100644 (file)
@@ -2,14 +2,8 @@
  * ndis_events - Receive NdisMIndicateStatus() events using WMI
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #define _WIN32_WINNT    0x0400
index 6778907..6c60550 100644 (file)
@@ -2,14 +2,8 @@
  * Netlink helper functions for driver wrappers
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -103,8 +97,6 @@ struct netlink_data * netlink_init(struct netlink_config *cfg)
        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 "
@@ -127,6 +119,8 @@ struct netlink_data * netlink_init(struct netlink_config *cfg)
        eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
                                 NULL);
 
+       netlink->cfg = cfg;
+
        return netlink;
 }
 
index ccf12a5..3a7340e 100644 (file)
@@ -2,14 +2,8 @@
  * Netlink helper functions for driver wrappers
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef NETLINK_H
index f9261c2..32b060e 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <linux/types.h>
 
+#define NL80211_GENL_NAME "nl80211"
+
 /**
  * DOC: Station handling
  *
  * The station is still assumed to belong to the AP interface it was added
  * to.
  *
- * TODO: need more info?
+ * Station handling varies per interface type and depending on the driver's
+ * capabilities.
+ *
+ * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
+ * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
+ *  - a setup station entry is added, not yet authorized, without any rate
+ *    or capability information, this just exists to avoid race conditions
+ *  - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
+ *    to add rate and capability information to the station and at the same
+ *    time mark it authorized.
+ *  - %NL80211_TDLS_ENABLE_LINK is then used
+ *  - after this, the only valid operation is to remove it by tearing down
+ *    the TDLS link (%NL80211_TDLS_DISABLE_LINK)
+ *
+ * TODO: need more info for other interface types
  */
 
 /**
  *     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_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
+ *     attributes determining the channel width; this is used for setting
+ *     monitor mode channel),  %NL80211_ATTR_WIPHY_RETRY_SHORT,
  *     %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
  *     and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
  *     However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
  * @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.
- *     Following attributes are provided for drivers that generate full Beacon
- *     and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @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, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- *     %NL80211_ATTR_IE_ASSOC_RESP.
- * @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_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
+ *     %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
+ *     The channel to use can be set on the interface or be given using the
+ *     %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
+ * @NL80211_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_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
  *     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,
+ *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ *     %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.
  *     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.
+ *     frequency for the operation.
  *     %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
  *     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
+ *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ 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.
  *     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.
  *     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.
+ *     and the attributes determining channel width) 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
  * @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
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH,
+ *      @NL80211_MESH_SETUP_USERSPACE_AMPE, or
+ *      @NL80211_MESH_SETUP_USERSPACE_MPM 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.
  *     command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
  *     more background information, see
  *     http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *     The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
+ *     from the driver reporting the wakeup reason. In this case, the
+ *     @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
+ *     for the wakeup, if it was caused by wireless. If it is not present
+ *     in the wakeup notification, the wireless device didn't cause the
+ *     wakeup but reports that it was woken up.
  *
  * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
  *     the necessary information for supporting GTK rekey offload. This
  *     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
  *     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 and the
+ *     attributes determining channel width.
+ *
+ * @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_SET_MAC_ACL: sets ACL for MAC address based access control.
+ *     This is to be used with the drivers advertising the support of MAC
+ *     address based access control. List of MAC addresses is passed in
+ *     %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in
+ *     %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it
+ *     is not already done. The new list will replace any existing list. Driver
+ *     will clear its ACL when the list of MAC addresses passed is empty. This
+ *     command is used in AP/P2P GO mode. Driver has to make sure to clear its
+ *     ACL list during %NL80211_CMD_STOP_AP.
+ *
+ * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
+ *     a radar is detected or the channel availability scan (CAC) has finished
+ *     or was aborted, or a radar was detected, usermode will be notified with
+ *     this event. This command is also used to notify userspace about radars
+ *     while operating on this channel.
+ *     %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
+ *     event.
+ *
+ * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
+ *     i.e. features for the nl80211 protocol rather than device features.
+ *     Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
+ *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ *     Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ *     to the supplicant. This will carry the target AP's MAC address along
+ *     with the relevant Information Elements. This event is used to report
+ *     received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running
+ *     a critical protocol that needs more reliability in the connection to
+ *     complete.
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
+ *     return back to normal.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -562,8 +672,10 @@ enum nl80211_commands {
 
        NL80211_CMD_GET_BEACON,
        NL80211_CMD_SET_BEACON,
-       NL80211_CMD_NEW_BEACON,
-       NL80211_CMD_DEL_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,
@@ -675,6 +787,29 @@ enum nl80211_commands {
 
        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,
+
+       NL80211_CMD_SET_MAC_ACL,
+
+       NL80211_CMD_RADAR_DETECT,
+
+       NL80211_CMD_GET_PROTOCOL_FEATURES,
+
+       NL80211_CMD_UPDATE_FT_IES,
+       NL80211_CMD_FT_EVENT,
+
+       NL80211_CMD_CRIT_PROTOCOL_START,
+       NL80211_CMD_CRIT_PROTOCOL_STOP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -711,14 +846,26 @@ enum nl80211_commands {
  *     /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_FREQ: frequency of the selected channel in MHz,
+ *     defines the channel together with the (deprecated)
+ *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
+ *     %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
+ *     and %NL80211_ATTR_CENTER_FREQ2
+ * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
+ *     of &enum nl80211_chan_width, describing the channel width. See the
+ *     documentation of the enum for more information.
+ * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
+ *     channel, used for anything but 20 MHz bandwidth
+ * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
+ *     channel, used only for 80+80 MHz bandwidth
  * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
- *     if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *     if HT20 or HT40 are to be used (i.e., HT 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
+ *     This attribute is now deprecated.
  * @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
@@ -738,6 +885,9 @@ enum nl80211_commands {
  * @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
@@ -748,6 +898,13 @@ enum nl80211_commands {
  *     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
@@ -772,7 +929,8 @@ enum nl80211_commands {
  *     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_STA_PLINK_ACTION: action to perform on the mesh peer link
+ *     (see &enum nl80211_plink_action).
  * @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
@@ -875,7 +1033,7 @@ enum nl80211_commands {
  * @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
+ *     with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
  *
  * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
  *     &struct nl80211_sta_flag_update.
@@ -983,6 +1141,8 @@ enum nl80211_commands {
  * @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.
  *
@@ -1040,7 +1200,7 @@ enum nl80211_commands {
  *     flag isn't set, the frame will be rejected. This is also used as an
  *     nl80211 capability flag.
  *
- * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ * @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.
@@ -1053,10 +1213,10 @@ enum nl80211_commands {
  * @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_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 or
+ *     @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled.
  *
  * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
  *     capabilities, the supported WoWLAN triggers
@@ -1064,10 +1224,10 @@ enum nl80211_commands {
  *     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
@@ -1094,7 +1254,7 @@ enum nl80211_commands {
  *     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
+ * @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,
@@ -1161,7 +1321,6 @@ enum nl80211_commands {
  * @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).
@@ -1169,6 +1328,113 @@ enum nl80211_commands {
  * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
  *     probe-response frame. The DA field in the 802.11 header is zero-ed out,
  *     to be filled by the FW.
+ * @NL80211_ATTR_DISABLE_HT:  Force HT capable interfaces to disable
+ *      this feature.  Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_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_P2P_CTWINDOW: P2P GO Client Traffic Window (u8), used with
+ *     the START_AP and SET_BSS commands
+ * @NL80211_ATTR_P2P_OPPPS: P2P GO opportunistic PS (u8), used with the
+ *     START_AP and SET_BSS commands. This can have the values 0 or 1;
+ *     if not given in START_AP 0 is assumed, if not given in SET_BSS
+ *     no change is made.
+ *
+ * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
+ *     defined in &enum nl80211_mesh_power_mode.
+ *
+ * @NL80211_ATTR_ACL_POLICY: ACL policy, see &enum nl80211_acl_policy,
+ *     carried in a u32 attribute
+ *
+ * @NL80211_ATTR_MAC_ADDRS: Array of nested MAC addresses, used for
+ *     MAC ACL.
+ *
+ * @NL80211_ATTR_MAC_ACL_MAX: u32 attribute to advertise the maximum
+ *     number of MAC addresses that a device can support for MAC
+ *     ACL.
+ *
+ * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace,
+ *     contains a value of enum nl80211_radar_event (u32).
+ *
+ * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver
+ *     has and handles. The format is the same as the IE contents. See
+ *     802.11-2012 8.4.2.29 for more information.
+ * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver
+ *     has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields.
+ *
+ * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to
+ *     the driver, e.g., to enable TDLS power save (PU-APSD).
+ *
+ * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are
+ *     advertised to the driver, e.g., to enable TDLS off channel operations
+ *     and PU-APSD.
+ *
+ * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
+ *     &enum nl80211_protocol_features, the attribute is a u32.
+ *
+ * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
+ *     receiving the data for a single wiphy split across multiple
+ *     messages, given with wiphy dump message
+ *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information
+ *     Element
+ *
+ * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased
+ *     reliability, see &enum nl80211_crit_proto_id (u16).
+ * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which
+ *      the connection should have increased reliability (u16).
+ *
+ * @NL80211_ATTR_PEER_AID: Association ID for the peer TDLS station (u16).
+ *     This is similar to @NL80211_ATTR_STA_AID but with a difference of being
+ *     allowed to be used with the first @NL80211_CMD_SET_STATION command to
+ *     update a TDLS peer STA entry.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1408,6 +1674,68 @@ enum nl80211_attrs {
 
        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,
+
+       NL80211_ATTR_CHANNEL_WIDTH,
+       NL80211_ATTR_CENTER_FREQ1,
+       NL80211_ATTR_CENTER_FREQ2,
+
+       NL80211_ATTR_P2P_CTWINDOW,
+       NL80211_ATTR_P2P_OPPPS,
+
+       NL80211_ATTR_LOCAL_MESH_POWER_MODE,
+
+       NL80211_ATTR_ACL_POLICY,
+
+       NL80211_ATTR_MAC_ADDRS,
+
+       NL80211_ATTR_MAC_ACL_MAX,
+
+       NL80211_ATTR_RADAR_EVENT,
+
+       NL80211_ATTR_EXT_CAPA,
+       NL80211_ATTR_EXT_CAPA_MASK,
+
+       NL80211_ATTR_STA_CAPABILITY,
+       NL80211_ATTR_STA_EXT_CAPABILITY,
+
+       NL80211_ATTR_PROTOCOL_FEATURES,
+       NL80211_ATTR_SPLIT_WIPHY_DUMP,
+
+       NL80211_ATTR_DISABLE_VHT,
+       NL80211_ATTR_VHT_CAPABILITY_MASK,
+
+       NL80211_ATTR_MDID,
+       NL80211_ATTR_IE_RIC,
+
+       NL80211_ATTR_CRIT_PROT_ID,
+       NL80211_ATTR_MAX_CRIT_PROT_DURATION,
+
+       NL80211_ATTR_PEER_AID,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1445,15 +1773,24 @@ enum nl80211_attrs {
 #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
  *
@@ -1469,6 +1806,10 @@ enum nl80211_attrs {
  * @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
  *
@@ -1487,6 +1828,7 @@ enum nl80211_iftype {
        NL80211_IFTYPE_MESH_POINT,
        NL80211_IFTYPE_P2P_CLIENT,
        NL80211_IFTYPE_P2P_GO,
+       NL80211_IFTYPE_P2P_DEVICE,
 
        /* keep last */
        NUM_NL80211_IFTYPES,
@@ -1506,7 +1848,14 @@ enum nl80211_iftype {
  * @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
+ * @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_ASSOCIATED: station is associated; used with drivers
+ *     that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
+ *     previously added station into associated state
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1518,12 +1867,15 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_MFP,
        NL80211_STA_FLAG_AUTHENTICATED,
        NL80211_STA_FLAG_TDLS_PEER,
+       NL80211_STA_FLAG_ASSOCIATED,
 
        /* 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
@@ -1541,13 +1893,26 @@ struct nl80211_sta_flag_update {
  *
  * 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_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_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -1556,6 +1921,12 @@ enum nl80211_rate_info {
        NL80211_RATE_INFO_MCS,
        NL80211_RATE_INFO_40_MHZ_WIDTH,
        NL80211_RATE_INFO_SHORT_GI,
+       NL80211_RATE_INFO_BITRATE32,
+       NL80211_RATE_INFO_VHT_MCS,
+       NL80211_RATE_INFO_VHT_NSS,
+       NL80211_RATE_INFO_80_MHZ_WIDTH,
+       NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+       NL80211_RATE_INFO_160_MHZ_WIDTH,
 
        /* keep last */
        __NL80211_RATE_INFO_AFTER_LAST,
@@ -1602,6 +1973,8 @@ enum nl80211_sta_bss_param {
  * @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_RX_BYTES64: total received bytes (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, 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
@@ -1621,6 +1994,16 @@ enum nl80211_sta_bss_param {
  *     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_LOCAL_PM: local mesh STA link-specific power mode
+ * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
+ * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
+ *     non-peer STA
+ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
+ *     Contains a nested array of signal strength attributes (u8, dBm)
+ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
+ *     Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -1643,6 +2026,15 @@ enum nl80211_sta_info {
        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,
+       NL80211_STA_INFO_LOCAL_PM,
+       NL80211_STA_INFO_PEER_PM,
+       NL80211_STA_INFO_NONPEER_PM,
+       NL80211_STA_INFO_RX_BYTES64,
+       NL80211_STA_INFO_TX_BYTES64,
+       NL80211_STA_INFO_CHAIN_SIGNAL,
+       NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -1712,6 +2104,9 @@ enum nl80211_mpath_info {
  * @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
  */
@@ -1725,6 +2120,9 @@ enum nl80211_band_attr {
        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
@@ -1746,6 +2144,20 @@ enum nl80211_band_attr {
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
  *     (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
+ *     (enum nl80211_dfs_state)
+ * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
+ *     this channel is in this DFS state.
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this
+ *     channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this
+ *     channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel
+ *     as the primary or any of the secondary channels isn't possible,
+ *     this includes 80+80 channels
+ * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
+ *     using this channel as the primary or any of the secondary channels
+ *     isn't possible
  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
  *     currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -1758,6 +2170,12 @@ enum nl80211_frequency_attr {
        NL80211_FREQUENCY_ATTR_NO_IBSS,
        NL80211_FREQUENCY_ATTR_RADAR,
        NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+       NL80211_FREQUENCY_ATTR_DFS_STATE,
+       NL80211_FREQUENCY_ATTR_DFS_TIME,
+       NL80211_FREQUENCY_ATTR_NO_HT40_MINUS,
+       NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
+       NL80211_FREQUENCY_ATTR_NO_80MHZ,
+       NL80211_FREQUENCY_ATTR_NO_160MHZ,
 
        /* keep last */
        __NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -1876,6 +2294,8 @@ enum nl80211_reg_rule_attr {
  * @__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
@@ -1883,7 +2303,8 @@ enum nl80211_reg_rule_attr {
 enum nl80211_sched_scan_match_attr {
        __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
 
-       NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -1891,6 +2312,9 @@ enum nl80211_sched_scan_match_attr {
                __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
  *
@@ -1917,6 +2341,41 @@ enum nl80211_reg_rule_flags {
 };
 
 /**
+ * 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
@@ -1987,6 +2446,34 @@ enum nl80211_mntr_flags {
 };
 
 /**
+ * enum nl80211_mesh_power_mode - mesh power save modes
+ *
+ * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is
+ *     not known or has not been set yet.
+ * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is
+ *     in Awake state all the time.
+ * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will
+ *     alternate between Active and Doze states, but will wake up for
+ *     neighbor's beacons.
+ * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will
+ *     alternate between Active and Doze states, but may not wake up
+ *     for neighbor's beacons.
+ *
+ * @__NL80211_MESH_POWER_AFTER_LAST - internal use
+ * @NL80211_MESH_POWER_MAX - highest possible power save level
+ */
+
+enum nl80211_mesh_power_mode {
+       NL80211_MESH_POWER_UNKNOWN,
+       NL80211_MESH_POWER_ACTIVE,
+       NL80211_MESH_POWER_LIGHT_SLEEP,
+       NL80211_MESH_POWER_DEEP_SLEEP,
+
+       __NL80211_MESH_POWER_AFTER_LAST,
+       NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_meshconf_params - mesh configuration parameters
  *
  * Mesh configuration parameters. These can be changed while the mesh is
@@ -1995,62 +2482,98 @@ enum nl80211_mntr_flags {
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
+ *     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
+ *     millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
+ *     millisecond units
  *
  * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
+ *     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
+ *     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.
+ *     point.
  *
- * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open
+ *     peer links when we detect compatible mesh peers. Disabled if
+ *     @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are
+ *     set.
  *
  * @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)
+ *     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)
+ *     (in milliseconds)
  *
  * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
+ *     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)
+ *     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
+ *     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
+ *     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.
+ *     source mesh point for path selection elements.
  *
  * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
- * root announcements are transmitted.
+ *     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.
+ *     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_POWER_MODE: Default mesh power mode for new peer links.
+ *     type &enum nl80211_mesh_power_mode (u32)
+ *
+ * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2072,6 +2595,16 @@ enum nl80211_meshconf_params {
        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,
+       NL80211_MESHCONF_POWER_MODE,
+       NL80211_MESHCONF_AWAKE_WINDOW,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2087,30 +2620,44 @@ enum nl80211_meshconf_params {
  * @__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.
+ *     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.
+ *     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.
+ *     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.
+ *     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.
+ *     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_USERSPACE_MPM: Enable this option if userspace will
+ *     implement an MPM which handles peer allocation and state.
+ *
+ * @NL80211_MESH_SETUP_AUTH_PROTOCOL: Inform the kernel of the authentication
+ *     method (u8, as defined in IEEE 8.4.2.100.6, e.g. 0x1 for SAE).
+ *     Default is no authentication method required.
  *
  * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
  */
 enum nl80211_mesh_setup_params {
@@ -2120,6 +2667,9 @@ enum nl80211_mesh_setup_params {
        NL80211_MESH_SETUP_IE,
        NL80211_MESH_SETUP_USERSPACE_AUTH,
        NL80211_MESH_SETUP_USERSPACE_AMPE,
+       NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
+       NL80211_MESH_SETUP_USERSPACE_MPM,
+       NL80211_MESH_SETUP_AUTH_PROTOCOL,
 
        /* keep last */
        __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -2129,7 +2679,7 @@ enum nl80211_mesh_setup_params {
 /**
  * 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_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
@@ -2142,7 +2692,7 @@ enum nl80211_mesh_setup_params {
  */
 enum nl80211_txq_attr {
        __NL80211_TXQ_ATTR_INVALID,
-       NL80211_TXQ_ATTR_QUEUE,
+       NL80211_TXQ_ATTR_AC,
        NL80211_TXQ_ATTR_TXOP,
        NL80211_TXQ_ATTR_CWMIN,
        NL80211_TXQ_ATTR_CWMAX,
@@ -2153,13 +2703,30 @@ enum nl80211_txq_attr {
        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_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 - channel type
+ * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_HT20: 20 MHz HT channel
+ * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
+ *     below the control channel
+ * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
+ *     above the control channel
+ */
 enum nl80211_channel_type {
        NL80211_CHAN_NO_HT,
        NL80211_CHAN_HT20,
@@ -2168,6 +2735,32 @@ enum nl80211_channel_type {
 };
 
 /**
+ * enum nl80211_chan_width - channel width definitions
+ *
+ * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
+ * attribute.
+ *
+ * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
+ * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
+ * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ */
+enum nl80211_chan_width {
+       NL80211_CHAN_WIDTH_20_NOHT,
+       NL80211_CHAN_WIDTH_20,
+       NL80211_CHAN_WIDTH_40,
+       NL80211_CHAN_WIDTH_80,
+       NL80211_CHAN_WIDTH_80P80,
+       NL80211_CHAN_WIDTH_160,
+};
+
+/**
  * enum nl80211_bss - netlink attributes for a BSS
  *
  * @__NL80211_BSS_INVALID: invalid
@@ -2235,6 +2828,7 @@ enum nl80211_bss_status {
  * @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
@@ -2246,6 +2840,7 @@ enum nl80211_auth_type {
        NL80211_AUTHTYPE_SHARED_KEY,
        NL80211_AUTHTYPE_FT,
        NL80211_AUTHTYPE_NETWORK_EAP,
+       NL80211_AUTHTYPE_SAE,
 
        /* keep last */
        __NL80211_AUTHTYPE_NUM,
@@ -2345,12 +2940,15 @@ enum nl80211_key_attributes {
  *     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,
@@ -2361,12 +2959,19 @@ enum nl80211_tx_rate_attributes {
  * 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,
@@ -2384,6 +2989,17 @@ enum nl80211_ps_state {
  * @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
  */
@@ -2393,6 +3009,9 @@ enum nl80211_attr_cqm {
        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,
@@ -2405,10 +3024,14 @@ enum nl80211_attr_cqm {
  *      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,
 };
 
 
@@ -2436,10 +3059,12 @@ enum nl80211_tx_power_setting {
  *     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".
+ *     twelve zero bytes, and a mask of "0xed,0x01".
  *     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.
+ * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ *     these fixed number of bytes of received packet
  * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
  * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
  */
@@ -2447,6 +3072,7 @@ enum nl80211_wowlan_packet_pattern_attr {
        __NL80211_WOWLAN_PKTPAT_INVALID,
        NL80211_WOWLAN_PKTPAT_MASK,
        NL80211_WOWLAN_PKTPAT_PATTERN,
+       NL80211_WOWLAN_PKTPAT_OFFSET,
 
        NUM_NL80211_WOWLAN_PKTPAT,
        MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
@@ -2457,6 +3083,7 @@ enum nl80211_wowlan_packet_pattern_attr {
  * @max_patterns: maximum number of patterns supported
  * @min_pattern_len: minimum length of each pattern
  * @max_pattern_len: maximum length of each pattern
+ * @max_pkt_offset: maximum Rx packet offset
  *
  * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
  * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
@@ -2466,6 +3093,7 @@ struct nl80211_wowlan_pattern_support {
        __u32 max_patterns;
        __u32 min_pattern_len;
        __u32 max_pattern_len;
+       __u32 max_pkt_offset;
 } __attribute__((packed));
 
 /**
@@ -2481,12 +3109,17 @@ struct nl80211_wowlan_pattern_support {
  * @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.
+ *     Each pattern defines a wakeup packet. Packet offset is associated with
+ *     each pattern which is used while matching the pattern. 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.
+ *
+ *     When reporting wakeup. it is a u32 attribute containing the 0-based
+ *     index of the pattern that caused the wakeup, in the patterns passed
+ *     to the kernel when configuring.
  * @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)
@@ -2497,8 +3130,36 @@ struct nl80211_wowlan_pattern_support {
  * @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)
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains
+ *     the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame
+ *     may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN
+ *     attribute contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11
+ *     packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211
+ *     attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the
+ *     802.11 packet that caused the wakeup, e.g. a magic packet. The frame may
+ *     be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute
+ *     contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3
+ *     packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023
+ *     attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section
+ *     "TCP connection wakeup" for more details. This is a nested attribute
+ *     containing the exact information for establishing and keeping alive
+ *     the TCP connection.
+ * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the
+ *     wakeup packet was received on the TCP connection
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the
+ *     TCP connection was lost or failed to be established
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
+ *     the TCP connection ran out of tokens to use for data to send to the
+ *     service
  * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
  * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ *
+ * These nested attributes are used to configure the wakeup triggers and
+ * to report the wakeup reason(s).
  */
 enum nl80211_wowlan_triggers {
        __NL80211_WOWLAN_TRIG_INVALID,
@@ -2511,6 +3172,14 @@ enum nl80211_wowlan_triggers {
        NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
        NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
        NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+       NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211,
+       NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN,
+       NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023,
+       NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN,
+       NL80211_WOWLAN_TRIG_TCP_CONNECTION,
+       NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
+       NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
+       NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
 
        /* keep last */
        NUM_NL80211_WOWLAN_TRIG,
@@ -2518,6 +3187,116 @@ enum nl80211_wowlan_triggers {
 };
 
 /**
+ * DOC: TCP connection wakeup
+ *
+ * Some devices can establish a TCP connection in order to be woken up by a
+ * packet coming in from outside their network segment, or behind NAT. If
+ * configured, the device will establish a TCP connection to the given
+ * service, and periodically send data to that service. The first data
+ * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK.
+ * The data packets can optionally include a (little endian) sequence
+ * number (in the TCP payload!) that is generated by the device, and, also
+ * optionally, a token from a list of tokens. This serves as a keep-alive
+ * with the service, and for NATed connections, etc.
+ *
+ * During this keep-alive period, the server doesn't send any data to the
+ * client. When receiving data, it is compared against the wakeup pattern
+ * (and mask) and if it matches, the host is woken up. Similarly, if the
+ * connection breaks or cannot be established to start with, the host is
+ * also woken up.
+ *
+ * Developer's note: ARP offload is required for this, otherwise TCP
+ * response packets might not go through correctly.
+ */
+
+/**
+ * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence
+ * @start: starting value
+ * @offset: offset of sequence number in packet
+ * @len: length of the sequence value to write, 1 through 4
+ *
+ * Note: don't confuse with the TCP sequence number(s), this is for the
+ * keepalive packet payload. The actual value is written into the packet
+ * in little endian.
+ */
+struct nl80211_wowlan_tcp_data_seq {
+       __u32 start, offset, len;
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config
+ * @offset: offset of token in packet
+ * @len: length of each token
+ * @token_stream: stream of data to be used for the tokens, the length must
+ *     be a multiple of @len for this to make sense
+ */
+struct nl80211_wowlan_tcp_data_token {
+       __u32 offset, len;
+       __u8 token_stream[];
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token_feature - data token features
+ * @min_len: minimum token length
+ * @max_len: maximum token length
+ * @bufsize: total available token buffer size (max size of @token_stream)
+ */
+struct nl80211_wowlan_tcp_data_token_feature {
+       __u32 min_len, max_len, bufsize;
+};
+
+/**
+ * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters
+ * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address
+ *     (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because
+ *     route lookup when configured might be invalid by the time we suspend,
+ *     and doing a route lookup when suspending is no longer possible as it
+ *     might require ARP querying.
+ * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a
+ *     socket and port will be allocated
+ * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16)
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte.
+ *     For feature advertising, a u32 attribute holding the maximum length
+ *     of the data payload.
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration
+ *     (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature
+ *     advertising it is just a flag
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration,
+ *     see &struct nl80211_wowlan_tcp_data_token and for advertising see
+ *     &struct nl80211_wowlan_tcp_data_token_feature.
+ * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum
+ *     interval in feature advertising (u32)
+ * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
+ *     u32 attribute holding the maximum length
+ * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
+ *     feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ *     but on the TCP payload only.
+ * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
+ * @MAX_NL80211_WOWLAN_TCP: highest attribute number
+ */
+enum nl80211_wowlan_tcp_attrs {
+       __NL80211_WOWLAN_TCP_INVALID,
+       NL80211_WOWLAN_TCP_SRC_IPV4,
+       NL80211_WOWLAN_TCP_DST_IPV4,
+       NL80211_WOWLAN_TCP_DST_MAC,
+       NL80211_WOWLAN_TCP_SRC_PORT,
+       NL80211_WOWLAN_TCP_DST_PORT,
+       NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+       NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
+       NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
+       NL80211_WOWLAN_TCP_DATA_INTERVAL,
+       NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
+       NL80211_WOWLAN_TCP_WAKE_MASK,
+
+       /* keep last */
+       NUM_NL80211_WOWLAN_TCP,
+       MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1
+};
+
+/**
  * enum nl80211_iface_limit_attrs - limit attributes
  * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
  * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
@@ -2553,6 +3332,8 @@ enum nl80211_iface_limit_attrs {
  *     the infrastructure network's beacon interval.
  * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
  *     different channels may be used within this group.
+ * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
+ *     of supported channel widths for radar detection.
  * @NUM_NL80211_IFACE_COMB: number of attributes
  * @MAX_NL80211_IFACE_COMB: highest attribute number
  *
@@ -2585,6 +3366,7 @@ enum nl80211_if_combination_attrs {
        NL80211_IFACE_COMB_MAXNUM,
        NL80211_IFACE_COMB_STA_AP_BI_MATCH,
        NL80211_IFACE_COMB_NUM_CHANNELS,
+       NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
 
        /* keep last */
        NUM_NL80211_IFACE_COMB,
@@ -2624,6 +3406,23 @@ enum nl80211_plink_state {
        MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 };
 
+/**
+ * enum nl80211_plink_action - actions to perform in mesh peers
+ *
+ * @NL80211_PLINK_ACTION_NO_ACTION: perform no action
+ * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
+ * @NUM_NL80211_PLINK_ACTIONS: number of possible actions
+ */
+enum plink_actions {
+       NL80211_PLINK_ACTION_NO_ACTION,
+       NL80211_PLINK_ACTION_OPEN,
+       NL80211_PLINK_ACTION_BLOCK,
+
+       NUM_NL80211_PLINK_ACTIONS,
+};
+
+
 #define NL80211_KCK_LEN                        16
 #define NL80211_KEK_LEN                        16
 #define NL80211_REPLAY_CTR_LEN         8
@@ -2735,9 +3534,67 @@ enum nl80211_ap_sme_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.
+ * @NL80211_FEATURE_P2P_GO_CTWIN: P2P GO implementation supports CT Window
+ *     setting
+ * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic
+ *     powersave
+ * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state
+ *     transitions for AP clients. Without this flag (and if the driver
+ *     doesn't have the AP SME in the device) the driver supports adding
+ *     stations only when they're associated and adds them in associated
+ *     state (to later be transitioned into authorized), with this flag
+ *     they should be added before even sending the authentication reply
+ *     and then transitioned into authenticated, associated and authorized
+ *     states using station flags.
+ *     Note that even for drivers that support this, the default is to add
+ *     stations in authenticated/associated state, so to add unauthenticated
+ *     stations the authenticated/associated bits have to be set in the mask.
+ * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
+ *     (HT40, VHT 80/160 MHz) if this flag is set
+ * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh
+ *     Peering Management entity which may be implemented by registering for
+ *     beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
+ *     still generated by the driver.
  */
 enum nl80211_feature_flags {
-       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+       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,
+       NL80211_FEATURE_P2P_GO_CTWIN                    = 1 << 11,
+       NL80211_FEATURE_P2P_GO_OPPPS                    = 1 << 12,
+       /* bit 13 is reserved */
+       NL80211_FEATURE_ADVERTISE_CHAN_LIMITS           = 1 << 14,
+       NL80211_FEATURE_FULL_AP_CLIENT_STATE            = 1 << 15,
+       NL80211_FEATURE_USERSPACE_MPM                   = 1 << 16,
 };
 
 /**
@@ -2761,4 +3618,127 @@ enum nl80211_probe_resp_offload_support_attr {
        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: Connection request is rejected due to ACL.
+ */
+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,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ *     listed in ACL, i.e. allow all the stations which are not listed
+ *     in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ *     in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+       NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+       NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
+ * enum nl80211_radar_event - type of radar event for DFS operation
+ *
+ * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
+ * about detected radars or success of the channel available check (CAC)
+ *
+ * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is
+ *     now unusable.
+ * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished,
+ *     the channel is now available.
+ * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no
+ *     change to the channel status.
+ * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
+ *     over, channel becomes usable.
+ */
+enum nl80211_radar_event {
+       NL80211_RADAR_DETECTED,
+       NL80211_RADAR_CAC_FINISHED,
+       NL80211_RADAR_CAC_ABORTED,
+       NL80211_RADAR_NOP_FINISHED,
+};
+
+/**
+ * enum nl80211_dfs_state - DFS states for channels
+ *
+ * Channel states used by the DFS code.
+ *
+ * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
+ *     check (CAC) must be performed before using it for AP or IBSS.
+ * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
+ *     is therefore marked as not available.
+ * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
+ */
+
+enum nl80211_dfs_state {
+       NL80211_DFS_USABLE,
+       NL80211_DFS_UNAVAILABLE,
+       NL80211_DFS_AVAILABLE,
+};
+
+/**
+ * enum enum nl80211_protocol_features - nl80211 protocol features
+ * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
+ *     wiphy dumps (if requested by the application with the attribute
+ *     %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
+ *     wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
+ *     %NL80211_ATTR_WDEV.
+ */
+enum nl80211_protocol_features {
+       NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP =     1 << 0,
+};
+
+/**
+ * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers
+ *
+ * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified.
+ * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol.
+ * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol.
+ * @NL80211_CRIT_PROTO_APIPA: APIPA protocol.
+ * @NUM_NL80211_CRIT_PROTO: must be kept last.
+ */
+enum nl80211_crit_proto_id {
+       NL80211_CRIT_PROTO_UNSPEC,
+       NL80211_CRIT_PROTO_DHCP,
+       NL80211_CRIT_PROTO_EAPOL,
+       NL80211_CRIT_PROTO_APIPA,
+       /* add other protocols before this one */
+       NUM_NL80211_CRIT_PROTO
+};
+
+/* maximum duration for critical protocol measures */
+#define NL80211_CRIT_PROTO_MAX_DURATION                5000 /* msec */
+
 #endif /* __LINUX_NL80211_H */
index 23eff83..74d6ce5 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PRIV_NETLINK_H
index 8818311..45b26c4 100644 (file)
@@ -2,14 +2,8 @@
  * Linux rfkill helper functions for driver wrappers
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 7a984a6..0412ac3 100644 (file)
@@ -2,14 +2,8 @@
  * Linux rfkill helper functions for driver wrappers
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RFKILL_H
index 60bfc1c..820d18a 100644 (file)
@@ -2,14 +2,8 @@
  * CHAP-MD5 (RFC 1994)
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index b9c400c..a791505 100644 (file)
@@ -2,14 +2,8 @@
  * CHAP-MD5 (RFC 1994)
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CHAP_H
index 4afa1dd..7b077cb 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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
@@ -41,19 +70,11 @@ const u8 * eap_hdr_validate(int vendor, EapType eap_type,
        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");
+       if (!eap_hdr_len_valid(msg, 1))
                return NULL;
-       }
 
+       hdr = wpabuf_head(msg);
        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) {
index b95e76b..8850c1f 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_COMMON_H
@@ -17,6 +11,7 @@
 
 #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,
index 3035301..0d247c4 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: Shared EAP definitions
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_DEFS_H
@@ -66,7 +60,7 @@ typedef enum {
        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_AKA_PRIME = 50 /* RFC 5448 */,
        EAP_TYPE_GPSK = 51 /* RFC 5433 */,
        EAP_TYPE_PWD = 52 /* RFC 5931 */,
        EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
@@ -77,9 +71,13 @@ typedef enum {
 enum {
        EAP_VENDOR_IETF = 0,
        EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
-       EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
+       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
 
index d3406f3..04b987d 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-FAST common helper functions (RFC 4851)
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index c85fd37..8955617 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-FAST definitions (RFC 4851)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_FAST_H
index 4076262..7a33215 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-GPSK shared routines
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -346,6 +340,141 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
 }
 
 
+static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
+                                     u8 *kdf_out, size_t kdf_out_len,
+                                     const u8 *psk, const u8 *seed,
+                                     size_t seed_len, u8 method_type)
+{
+       u8 *pos, *data;
+       size_t data_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;
+               break;
+#ifdef EAP_GPSK_SHA256
+       case EAP_GPSK_CIPHER_SHA256:
+               gkdf = eap_gpsk_gkdf_sha256;
+               break;
+#endif /* EAP_GPSK_SHA256 */
+       default:
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
+                          "Session-Id derivation", csuite_specifier);
+               return -1;
+       }
+
+#define SID_LABEL "Method ID"
+       /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
+       data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
+       pos += strlen(SID_LABEL);
+#undef SID_LABEL
+       os_memcpy(pos, &method_type, 1);
+       pos += 1;
+       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(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
+                   data, data_len);
+
+       if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
+               os_free(data);
+               return -1;
+       }
+       os_free(data);
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
+
+       return 0;
+}
+
+
+/**
+ * eap_gpsk_session_id - Derive EAP-GPSK Session ID
+ * @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
+ * @method_type: EAP Authentication Method Type
+ * @sid: Buffer for 17-byte Session ID
+ * @sid_len: Buffer for returning length of Session ID
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_session_id(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 method_type, u8 *sid, size_t *sid_len)
+{
+       u8 *seed, *pos;
+       u8 kdf_out[16];
+       size_t seed_len;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
+                  vendor, specifier);
+
+       if (vendor != EAP_GPSK_VENDOR_IETF)
+               return -1;
+
+       wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+       /*
+        * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+        *            (= seed)
+        * KS = 16, CSuite_Sel = 0x00000000 0x0001
+        * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+        *                      CSuite_Sel || inputString)
+        */
+       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 Session-Id 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);
+
+       ret = eap_gpsk_derive_mid_helper(specifier,
+                                        kdf_out, sizeof(kdf_out),
+                                        psk, seed, seed_len,
+                                        method_type);
+
+       sid[0] = method_type;
+       os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
+       *sid_len = 1 + sizeof(kdf_out);
+
+       os_free(seed);
+
+       return ret;
+}
+
+
 /**
  * eap_gpsk_mic_len - Get the length of the MIC
  * @vendor: CSuite/Vendor
index a30ab97..fbcd547 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-GPSK shared routines
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_GPSK_COMMON_H
@@ -59,6 +53,12 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
                         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);
+int eap_gpsk_derive_session_id(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 method_type, u8 *sid, size_t *sid_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);
index e9a9c55..6095fd8 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-IKEv2 common routines
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index a9fc2ca..329ccc4 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-IKEv2 definitions
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_IKEV2_COMMON_H
index 32dc80c..b3bbacc 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-PAX shared routines
  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index dcc171e..fb03df2 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-PAX shared routines
  * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_PAX_COMMON_H
index 8a701d2..68b8878 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-PEAP common routines
  * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f182078..7aad0df 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-PEAP common routines
  * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_PEAP_COMMON_H
index 7417d5c..638102f 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-PSK shared routines
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 8adc054..8bc2c3c 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-PSK shared routines
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_PSK_COMMON_H
index 0dbdff2..7d6e6b8 100644 (file)
@@ -2,82 +2,82 @@
  * EAP server/peer: EAP-pwd shared routines
  * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD license.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * See README and COPYING for more details.
+ * 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) */
-void H_Init(HMAC_CTX *ctx)
+struct crypto_hash * eap_pwd_h_init(void)
 {
-       u8 allzero[SHA256_DIGEST_LENGTH];
-
-       os_memset(allzero, 0, SHA256_DIGEST_LENGTH);
-       HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
+       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 H_Update(HMAC_CTX *ctx, const u8 *data, int len)
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len)
 {
-       HMAC_Update(ctx, data, len);
+       crypto_hash_update(hash, data, len);
 }
 
 
-void H_Final(HMAC_CTX *ctx, u8 *digest)
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
 {
-       unsigned int mdlen = SHA256_DIGEST_LENGTH;
-
-       HMAC_Final(ctx, digest, &mdlen);
-       HMAC_CTX_cleanup(ctx);
+       size_t len = SHA256_MAC_LEN;
+       crypto_hash_finish(hash, digest, &len);
 }
 
 
 /* a counter-based KDF based on NIST SP800-108 */
-void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen,
-                u8 *result, int resultbitlen)
+static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
+                      size_t labellen, u8 *result, size_t resultbitlen)
 {
-       HMAC_CTX hctx;
-       unsigned char digest[SHA256_DIGEST_LENGTH];
+       struct crypto_hash *hash;
+       u8 digest[SHA256_MAC_LEN];
        u16 i, ctr, L;
-       int resultbytelen, len = 0;
-       unsigned int mdlen = SHA256_DIGEST_LENGTH;
-       unsigned char mask = 0xff;
+       size_t resultbytelen, len = 0, mdlen;
 
-       resultbytelen = (resultbitlen + 7)/8;
+       resultbytelen = (resultbitlen + 7) / 8;
        ctr = 0;
        L = htons(resultbitlen);
        while (len < resultbytelen) {
-               ctr++; i = htons(ctr);
-               HMAC_Init(&hctx, key, keylen, EVP_sha256());
+               ctr++;
+               i = htons(ctr);
+               hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256,
+                                       key, keylen);
+               if (hash == NULL)
+                       return -1;
                if (ctr > 1)
-                       HMAC_Update(&hctx, digest, mdlen);
-               HMAC_Update(&hctx, (u8 *) &i, sizeof(u16));
-               HMAC_Update(&hctx, label, labellen);
-               HMAC_Update(&hctx, (u8 *) &L, sizeof(u16));
-               HMAC_Final(&hctx, digest, &mdlen);
-               if ((len + (int) mdlen) > resultbytelen)
+                       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;
-               HMAC_CTX_cleanup(&hctx);
        }
 
        /* 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;
 }
 
 
@@ -91,9 +91,10 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
                             u8 *id_peer, int id_peer_len, u8 *token)
 {
        BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
-       HMAC_CTX ctx;
-       unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
-       int nid, is_odd, primebitlen, primebytelen, ret = 0;
+       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:
@@ -160,7 +161,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
        os_memset(prfbuf, 0, primebytelen);
        ctr = 0;
        while (1) {
-               if (ctr > 10) {
+               if (ctr > 30) {
                        wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
                                   "point on curve for group %d, something's "
                                   "fishy", num);
@@ -173,20 +174,23 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
                 *    pwd-seed = H(token | peer-id | server-id | password |
                 *                 counter)
                 */
-               H_Init(&ctx);
-               H_Update(&ctx, token, sizeof(u32));
-               H_Update(&ctx, id_peer, id_peer_len);
-               H_Update(&ctx, id_server, id_server_len);
-               H_Update(&ctx, password, password_len);
-               H_Update(&ctx, &ctr, sizeof(ctr));
-               H_Final(&ctx, pwe_digest);
-
-               BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
-
-               eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
-                           (unsigned char *) "EAP-pwd Hunting And Pecking",
-                           os_strlen("EAP-pwd Hunting And Pecking"),
-                           prfbuf, primebitlen);
+               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);
 
@@ -258,11 +262,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 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);
-               os_free(grp);
-               grp = NULL;
+               grp->prime = NULL;
                ret = 1;
        }
        /* cleanliness and order.... */
@@ -277,12 +283,12 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
 
 int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
                 BIGNUM *peer_scalar, BIGNUM *server_scalar,
-                u8 *commit_peer, u8 *commit_server,
+                u8 *confirm_peer, u8 *confirm_server,
                 u32 *ciphersuite, u8 *msk, u8 *emsk)
 {
-       HMAC_CTX ctx;
-       u8 mk[SHA256_DIGEST_LENGTH], *cruft;
-       u8 session_id[SHA256_DIGEST_LENGTH + 1];
+       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;
 
@@ -294,37 +300,46 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
         *      scal_s)
         */
        session_id[0] = EAP_TYPE_PWD;
-       H_Init(&ctx);
-       H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->order));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->order));
-       H_Final(&ctx, &session_id[1]);
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+       eap_pwd_h_final(hash, &session_id[1]);
 
-       /* then compute MK = H(k | commit-peer | commit-server) */
-       H_Init(&ctx);
+       /* 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);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
-       H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH);
-       H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH);
-       H_Final(&ctx, mk);
+       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 */
-       eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
-                   session_id, SHA256_DIGEST_LENGTH+1,
-                   msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8);
+       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);
 
-       os_free(cruft);
-
        return 1;
 }
index 4b841b7..816e58c 100644 (file)
@@ -2,24 +2,16 @@
  * EAP server/peer: EAP-pwd shared definitions
  * Copyright (c) 2009, Dan Harkins <dharkins@lounge.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD license.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * See README and COPYING for more details.
+ * 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/sha.h>
 #include <openssl/ec.h>
 #include <openssl/evp.h>
-#include <openssl/hmac.h>
 
 /*
  * definition of a finite cyclic group
@@ -37,16 +29,17 @@ typedef struct group_definition_ {
  * 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)->lm_exch & 0x80)
-#define EAP_PWD_SET_LENGTH_BIT(x)       ((x)->lm_exch |= 0x80)
-#define EAP_PWD_GET_MORE_BIT(x)         ((x)->lm_exch & 0x40)
-#define EAP_PWD_SET_MORE_BIT(x)         ((x)->lm_exch |= 0x40)
-#define EAP_PWD_GET_EXCHANGE(x)         ((x)->lm_exch & 0x3f)
-#define EAP_PWD_SET_EXCHANGE(x,y)       ((x)->lm_exch |= (y))
+#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 {
@@ -67,8 +60,8 @@ 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 *);
-void H_Init(HMAC_CTX *);
-void H_Update(HMAC_CTX *, const u8 *, int);
-void H_Final(HMAC_CTX *, 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 */
index 9002b0c..a76253d 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-SAKE shared routines
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 201e207..9e1e757 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-SAKE shared routines
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_SAKE_COMMON_H
index 0b37b0b..e1773bf 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 48c8eaa..6021bd2 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_SIM_COMMON_H
index f86015d..3286055 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_TLV_COMMON_H
index 797d084..17901d4 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server/peer: EAP-TTLS (RFC 5281)
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_TTLS_H
index 5d4e8cc..7c1496e 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-WSC common routines for Wi-Fi Protected Setup
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index fdf61d3..0e7b653 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-WSC definitions for Wi-Fi Protected Setup
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_WSC_COMMON_H
index 003c288..376fcad 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 common routines for initiator and responder
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 31a2b0d..45c970b 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 definitions
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IKEV2_COMMON_H
index 91fa4a9..c0d7078 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -26,6 +20,7 @@
 #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"
@@ -87,8 +82,21 @@ static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
 }
 
 
+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;
 
@@ -153,6 +161,8 @@ SM_STATE(EAP, INITIALIZE)
        eapol_set_bool(sm, EAPOL_eapFail, FALSE);
        os_free(sm->eapKeyData);
        sm->eapKeyData = NULL;
+       os_free(sm->eapSessionId);
+       sm->eapSessionId = NULL;
        sm->eapKeyAvailable = FALSE;
        eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
        sm->lastId = -1; /* new session - make sure this does not match with
@@ -181,6 +191,12 @@ 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);
 }
 
 
@@ -219,6 +235,7 @@ SM_STATE(EAP, GET_METHOD)
 {
        int reinit;
        EapType method;
+       const struct eap_method *eap_method;
 
        SM_ENTRY(EAP, GET_METHOD);
 
@@ -227,18 +244,24 @@ SM_STATE(EAP, GET_METHOD)
        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
@@ -262,7 +285,7 @@ SM_STATE(EAP, GET_METHOD)
 
        sm->selectedMethod = sm->reqMethod;
        if (sm->m == NULL)
-               sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
+               sm->m = eap_method;
        if (!sm->m) {
                wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
                           "vendor %d method %d",
@@ -327,6 +350,7 @@ SM_STATE(EAP, METHOD)
 {
        struct wpabuf *eapReqData;
        struct eap_method_ret ret;
+       int min_len = 1;
 
        SM_ENTRY(EAP, METHOD);
        if (sm->m == NULL) {
@@ -335,6 +359,10 @@ SM_STATE(EAP, METHOD)
        }
 
        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
@@ -377,6 +405,15 @@ SM_STATE(EAP, METHOD)
                os_free(sm->eapKeyData);
                sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
                                               &sm->eapKeyDataLen);
+               os_free(sm->eapSessionId);
+               sm->eapSessionId = NULL;
+               if (sm->m->getSessionId) {
+                       sm->eapSessionId = sm->m->getSessionId(
+                               sm, sm->eap_method_priv,
+                               &sm->eapSessionIdLen);
+                       wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+                                   sm->eapSessionId, sm->eapSessionIdLen);
+               }
        }
 }
 
@@ -423,6 +460,8 @@ SM_STATE(EAP, IDENTITY)
 
        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;
@@ -439,6 +478,8 @@ SM_STATE(EAP, NOTIFICATION)
 
        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;
@@ -856,12 +897,17 @@ 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)
 {
-       const struct eap_hdr *hdr = wpabuf_head(req);
-       const u8 *pos = (const u8 *) (hdr + 1);
-       pos++;
+       const u8 *pos;
+       size_t msg_len;
 
        wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
                "EAP authentication started");
+       eap_notify_status(sm, "started", "");
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
+                              &msg_len);
+       if (pos == NULL)
+               return;
 
        /*
         * RFC 3748 - 5.1: Identity
@@ -873,15 +919,78 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
        /* 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);
+                         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)
 {
-       int aka = 0;
+       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;
@@ -895,11 +1004,28 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
 
        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) {
-                       aka = 1;
+                       method = EAP_SM_AKA;
                        break;
                }
        }
@@ -912,12 +1038,23 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
                return -1;
        }
 
-       conf->identity[0] = aka ? '0' : '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 */
 
 
@@ -1150,10 +1287,12 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
                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:
@@ -1171,6 +1310,10 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
        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'",
@@ -1178,6 +1321,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                        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)
@@ -1198,6 +1343,14 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                                          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);
@@ -1252,6 +1405,13 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
                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;
 }
 
@@ -1269,6 +1429,8 @@ void eap_peer_sm_deinit(struct eap_sm *sm)
                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);
 }
@@ -1311,6 +1473,8 @@ void eap_sm_abort(struct eap_sm *sm)
        sm->eapRespData = NULL;
        os_free(sm->eapKeyData);
        sm->eapKeyData = NULL;
+       os_free(sm->eapSessionId);
+       sm->eapSessionId = 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
@@ -1788,6 +1952,27 @@ const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
 }
 
 
+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()
@@ -1799,6 +1984,14 @@ 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;
 }
@@ -1818,6 +2011,14 @@ 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);
@@ -1971,6 +2172,28 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
 
 
 /**
+ * eap_get_eapSessionId - Get Session-Id 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 session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
+ * only after a successful authentication. EAP state machine continues to manage
+ * the Session-Id and the caller must not change or free the returned data.
+ */
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
+{
+       if (sm == NULL || sm->eapSessionId == NULL) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = sm->eapSessionIdLen;
+       return sm->eapSessionId;
+}
+
+
+/**
  * 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
@@ -2129,3 +2352,24 @@ int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
 
        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);
+}
index f35197f..f87f9b3 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer state machine functions (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_H
@@ -232,6 +226,23 @@ struct eapol_callbacks {
         */
        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);
 };
 
 /**
@@ -295,6 +306,7 @@ 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_eapSessionId(struct eap_sm *sm, size_t *len);
 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);
@@ -303,6 +315,10 @@ 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 */
index 766764b..dc424d7 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -96,6 +90,7 @@ 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)
@@ -108,6 +103,15 @@ static void * eap_aka_init(struct eap_sm *sm)
 
        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;
 }
 
@@ -233,21 +237,23 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 #define CLEAR_REAUTH_ID        0x02
 #define CLEAR_EAP_ID   0x04
 
-static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
+static void eap_aka_clear_identities(struct eap_sm *sm,
+                                    struct eap_aka_data *data, int id)
 {
-       if (id & CLEAR_PSEUDONYM) {
+       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) {
+       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) {
+       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;
@@ -256,24 +262,45 @@ static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 }
 
 
-static int eap_aka_learn_ids(struct eap_aka_data *data,
+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);
-               data->pseudonym = os_malloc(attr->next_pseudonym_len);
+               /* 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);
-               data->pseudonym_len = attr->next_pseudonym_len;
-               wpa_hexdump_ascii(MSG_DEBUG,
-                                 "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
-                                 data->pseudonym,
-                                 data->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) {
@@ -282,6 +309,7 @@ static int eap_aka_learn_ids(struct eap_aka_data *data,
                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,
@@ -410,6 +438,8 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
        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);
@@ -471,16 +501,16 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
                   data->pseudonym) {
                identity = data->pseudonym;
                identity_len = data->pseudonym_len;
-               eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
+               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(data, CLEAR_PSEUDONYM |
+                       eap_aka_clear_identities(sm, data, CLEAR_PSEUDONYM |
                                                 CLEAR_REAUTH_ID);
                }
        }
        if (id_req != NO_ID_REQ)
-               eap_aka_clear_identities(data, CLEAR_EAP_ID);
+               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,
@@ -883,7 +913,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
         * 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(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
@@ -894,7 +924,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
                        return eap_aka_client_error(
                                data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
                }
-               eap_aka_learn_ids(data, &eattr);
+               eap_aka_learn_ids(sm, data, &eattr);
                os_free(decrypted);
        }
 
@@ -1111,8 +1141,8 @@ static struct wpabuf * eap_aka_process_reauthentication(
                                           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);
+       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;
@@ -1127,7 +1157,8 @@ static struct wpabuf * eap_aka_process_reauthentication(
        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);
+               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);
@@ -1245,7 +1276,7 @@ static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
 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);
+       eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
        data->prev_id = -1;
        wpabuf_free(data->id_msgs);
        data->id_msgs = NULL;
@@ -1309,6 +1340,28 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_aka_data *data = priv;
+       u8 *id;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+       id = os_malloc(*len);
+       if (id == NULL)
+               return NULL;
+
+       id[0] = data->eap_method;
+       os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+       os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+       wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+       return id;
+}
+
+
 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_aka_data *data = priv;
@@ -1343,6 +1396,7 @@ int eap_peer_aka_register(void)
        eap->process = eap_aka_process;
        eap->isKeyAvailable = eap_aka_isKeyAvailable;
        eap->getKey = eap_aka_getKey;
+       eap->getSessionId = eap_aka_get_session_id;
        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;
@@ -1373,6 +1427,7 @@ int eap_peer_aka_prime_register(void)
        eap->process = eap_aka_process;
        eap->isKeyAvailable = eap_aka_isKeyAvailable;
        eap->getKey = eap_aka_getKey;
+       eap->getSessionId = eap_aka_get_session_id;
        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;
index b64b68f..42f525b 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer configuration data
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_CONFIG_H
@@ -41,6 +35,9 @@ struct eap_peer_config {
         *
         * 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;
 
@@ -625,6 +622,7 @@ struct eap_peer_config {
        int fragment_size;
 
 #define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
        /**
         * flags - Network configuration flags (bitfield)
         *
@@ -632,8 +630,19 @@ struct eap_peer_config {
         * for the network parameters.
         * bit 0 = password is represented as a 16-byte NtPasswordHash value
         *         instead of plaintext password
+        * bit 1 = password is stored in external storage; the value in the
+        *         password field is the name of that external entry
         */
        u32 flags;
+
+       /**
+        * ocsp - Whether to use/require OCSP to check server certificate
+        *
+        * 0 = do not use OCSP stapling (TLS certificate status extension)
+        * 1 = try to use OCSP stapling, but not require response
+        * 2 = require valid OCSP stapling response
+        */
+       int ocsp;
 };
 
 
index 3cfb41a..3b8d803 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-FAST (RFC 4851)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -59,6 +53,8 @@ struct eap_fast_data {
        int session_ticket_used;
 
        u8 key_data[EAP_FAST_KEY_LEN];
+       u8 *session_id;
+       size_t id_len;
        u8 emsk[EAP_EMSK_LEN];
        int success;
 
@@ -175,7 +171,7 @@ static void * eap_fast_init(struct eap_sm *sm)
        data->phase2_type.vendor = EAP_VENDOR_IETF;
        data->phase2_type.method = EAP_TYPE_NONE;
 
-       if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+       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;
@@ -244,6 +240,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
                pac = pac->next;
                eap_fast_free_pac(prev);
        }
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -791,6 +788,21 @@ static struct wpabuf * eap_fast_process_crypto_binding(
                return NULL;
        }
 
+       if (!data->anon_provisioning && data->phase2_success) {
+               os_free(data->session_id);
+               data->session_id = eap_peer_tls_derive_session_id(
+                       sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
+               if (data->session_id) {
+                       wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
+                                   data->session_id, data->id_len);
+               } else {
+                       wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
+                                  "Session-Id");
+                       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);
@@ -1610,6 +1622,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
                os_free(data);
                return NULL;
        }
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (data->phase2_priv && data->phase2_method &&
            data->phase2_method->init_for_reauth)
                data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@@ -1668,6 +1682,25 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_fast_data *data = priv;
+       u8 *id;
+
+       if (!data->success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_fast_data *data = priv;
@@ -1702,6 +1735,7 @@ int eap_peer_fast_register(void)
        eap->process = eap_fast_process;
        eap->isKeyAvailable = eap_fast_isKeyAvailable;
        eap->getKey = eap_fast_getKey;
+       eap->getSessionId = eap_fast_get_session_id;
        eap->get_status = eap_fast_get_status;
 #if 0
        eap->has_reauth_data = eap_fast_has_reauth_data;
index 4037288..8c480b9 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-FAST PAC file processing
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -428,8 +422,12 @@ int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
        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)
+       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) {
index 9483f96..8815d91 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-FAST PAC file processing
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_FAST_PAC_H
index 5037c60..8a0644d 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-GPSK (RFC 5433)
  * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -29,8 +23,8 @@ struct eap_gpsk_data {
        size_t sk_len;
        u8 pk[EAP_GPSK_MAX_PK_LEN];
        size_t pk_len;
-       u8 session_id;
-       int session_id_set;
+       u8 session_id[128];
+       size_t id_len;
        u8 *id_peer;
        size_t id_peer_len;
        u8 *id_server;
@@ -360,6 +354,21 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
                return NULL;
        }
 
+       if (eap_gpsk_derive_session_id(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,
+                                      EAP_TYPE_GPSK,
+                                      data->session_id, &data->id_len) < 0) {
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+               eap_gpsk_state(data, FAILURE);
+               wpabuf_free(resp);
+               return NULL;
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+                   data->session_id, data->id_len);
+
        /* No PD_Payload_1 */
        wpabuf_put_be16(resp, 0);
 
@@ -714,6 +723,24 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_gpsk_data *data = priv;
+       u8 *sid;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       sid = os_malloc(data->id_len);
+       if (sid == NULL)
+               return NULL;
+       os_memcpy(sid, data->session_id, data->id_len);
+       *len = data->id_len;
+
+       return sid;
+}
+
+
 int eap_peer_gpsk_register(void)
 {
        struct eap_method *eap;
@@ -730,6 +757,7 @@ int eap_peer_gpsk_register(void)
        eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
        eap->getKey = eap_gpsk_getKey;
        eap->get_emsk = eap_gpsk_get_emsk;
+       eap->getSessionId = eap_gpsk_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
index b2b554b..9f3cfbd 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-GTC (RFC 3748)
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index afca611..62c867c 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer state machines internal structures (RFC 4137)
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_I_H
@@ -267,6 +261,19 @@ struct eap_method {
         * private data or this function may derive the key.
         */
        u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+       /**
+        * getSessionId - Get EAP method specific Session-Id
+        * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+        * @priv: Pointer to private EAP method data from eap_method::init()
+        * @len: Pointer to a variable to store Session-Id length
+        * Returns: Session-Id or %NULL if not available
+        *
+        * This function can be used to get the Session-Id from the EAP method.
+        * The Session-Id may already be stored in the method-specific private
+        * data or this function may derive the Session-Id.
+        */
+       u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
 };
 
 
@@ -304,6 +311,8 @@ struct eap_sm {
        Boolean eapKeyAvailable; /* peer to lower layer */
        u8 *eapKeyData; /* peer to lower layer */
        size_t eapKeyDataLen; /* peer to lower layer */
+       u8 *eapSessionId; /* peer to lower layer */
+       size_t eapSessionIdLen; /* peer to lower layer */
        const struct eap_method *m; /* selected EAP method */
        /* not defined in RFC 4137 */
        Boolean changed;
@@ -323,6 +332,7 @@ struct eap_sm {
        void *msg_ctx;
        void *scard_ctx;
        void *ssl_ctx;
+       void *ssl_ctx2;
 
        unsigned int workaround;
 
@@ -335,6 +345,9 @@ struct eap_sm {
        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);
index bb49a66..09a655e 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-IKEv2 peer (RFC 5106)
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -481,6 +475,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_ikev2_data *data = priv;
+       u8 *sid;
+       size_t sid_len;
+       size_t offset;
+
+       if (data->state != DONE || !data->keymat_ok)
+               return NULL;
+
+       sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+       sid = os_malloc(sid_len);
+       if (sid) {
+               offset = 0;
+               sid[offset] = EAP_TYPE_IKEV2;
+               offset++;
+               os_memcpy(sid + offset, data->ikev2.i_nonce,
+                         data->ikev2.i_nonce_len);
+               offset += data->ikev2.i_nonce_len;
+               os_memcpy(sid + offset, data->ikev2.r_nonce,
+                         data->ikev2.r_nonce_len);
+               *len = sid_len;
+               wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+                           sid, sid_len);
+       }
+
+       return sid;
+}
+
+
 int eap_peer_ikev2_register(void)
 {
        struct eap_method *eap;
@@ -498,6 +522,7 @@ int eap_peer_ikev2_register(void)
        eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
        eap->getKey = eap_ikev2_getKey;
        eap->get_emsk = eap_ikev2_get_emsk;
+       eap->getSessionId = eap_ikev2_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
index 6a8efcd..df34013 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: LEAP
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0edbae8..d06befa 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -92,7 +86,13 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
 
        id = eap_get_id(resp);
        rpos = wpabuf_put(resp, CHAP_MD5_LEN);
-       chap_md5(id, password, password_len, challenge, challenge_len, rpos);
+       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;
index 937fd45..83a1457 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer: Method registration
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 4330b57..4994ff1 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer: Method registration
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_METHODS_H
@@ -91,6 +85,7 @@ static inline int eap_peer_method_unload(struct eap_method *method)
 /* 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);
index 321e9f7..f9aa742 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -310,7 +304,9 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm,
                        "EAP-MSCHAPV2: Password changed successfully");
                data->prev_error = 0;
                os_free(config->password);
-               if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
+               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) {
@@ -648,10 +644,8 @@ static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
         * must allocate a large enough temporary buffer to create that since
         * the received message does not include nul termination.
         */
-       buf = os_malloc(len + 1);
+       buf = dup_binstr(msdata, len);
        if (buf) {
-               os_memcpy(buf, msdata, len);
-               buf[len] = '\0';
                retry = eap_mschapv2_failure_txt(sm, data, buf);
                os_free(buf);
        }
index 556c22f..9ac744a 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-OTP (RFC 3748)
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index d42a7f8..7f87052 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-PAX (RFC 4746)
  * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 7cb8213..3b93209 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -62,6 +56,8 @@ struct eap_peap_data {
        int resuming; /* starting a resumed session */
        int reauth; /* reauthentication */
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
 
        struct wpabuf *pending_phase2_req;
        enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@@ -165,7 +161,7 @@ static void * eap_peap_init(struct eap_sm *sm)
        data->phase2_type.vendor = EAP_VENDOR_IETF;
        data->phase2_type.method = EAP_TYPE_NONE;
 
-       if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+       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;
@@ -185,6 +181,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        os_free(data->phase2_types);
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -1113,6 +1110,20 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                                           "derive key");
                        }
 
+                       os_free(data->session_id);
+                       data->session_id =
+                               eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                              EAP_TYPE_PEAP,
+                                                              &data->id_len);
+                       if (data->session_id) {
+                               wpa_hexdump(MSG_DEBUG,
+                                           "EAP-PEAP: Derived Session-Id",
+                                           data->session_id, data->id_len);
+                       } else {
+                               wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
+                                          "derive Session-Id");
+                       }
+
                        if (sm->workaround && data->resuming) {
                                /*
                                 * At least few RADIUS servers (Aegis v1.1.6;
@@ -1184,6 +1195,8 @@ 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;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -1266,6 +1279,25 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_peap_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL || !data->phase2_success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_peap_register(void)
 {
        struct eap_method *eap;
@@ -1285,6 +1317,7 @@ int eap_peer_peap_register(void)
        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;
+       eap->getSessionId = eap_peap_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
new file mode 100644 (file)
index 0000000..3b4dcef
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * EAP proxy definitions
+ * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PROXY_H
+#define EAP_PROXY_H
+
+struct eap_proxy_sm;
+struct eapol_callbacks;
+struct eap_sm;
+struct eap_peer_config;
+
+enum eap_proxy_status {
+       EAP_PROXY_FAILURE = 0x00,
+       EAP_PROXY_SUCCESS
+};
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+              void *msg_ctx);
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm);
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len);
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm);
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm);
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+                       int eapReqDataLen);
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+                           int verbose);
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+                           struct eap_peer_config *config);
+
+#endif /* EAP_PROXY_H */
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
new file mode 100644 (file)
index 0000000..cd97fb6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * EAP proxy - dummy implementation for build testing
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_proxy.h"
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+              void *msg_ctx)
+{
+       return NULL;
+}
+
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
+{
+}
+
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm)
+{
+       return 0;
+}
+
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len)
+{
+       return NULL;
+}
+
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm)
+{
+       return NULL;
+}
+
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm)
+{
+       return 0;
+}
+
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+                       int eapReqDataLen)
+{
+       return EAP_PROXY_FAILURE;
+}
+
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+                           int verbose)
+{
+       return 0;
+}
+
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+{
+       return -1;
+}
+
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+                           struct eap_peer_config *config)
+{
+       return -1;
+}
index 592ef13..cd0e3f9 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-PSK (RFC 4764)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
@@ -27,6 +21,7 @@
 struct eap_psk_data {
        enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
        u8 rand_p[EAP_PSK_RAND_LEN];
+       u8 rand_s[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;
@@ -118,6 +113,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
        }
        wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
                    EAP_PSK_RAND_LEN);
+       os_memcpy(data->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);
@@ -440,6 +436,28 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_psk_data *data = priv;
+       u8 *id;
+
+       if (data->state != PSK_DONE)
+               return NULL;
+
+       *len = 1 + 2 * EAP_PSK_RAND_LEN;
+       id = os_malloc(*len);
+       if (id == NULL)
+               return NULL;
+
+       id[0] = EAP_TYPE_PSK;
+       os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+       os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+       wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+       return id;
+}
+
+
 static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_psk_data *data = priv;
@@ -474,6 +492,7 @@ int eap_peer_psk_register(void)
        eap->process = eap_psk_process;
        eap->isKeyAvailable = eap_psk_isKeyAvailable;
        eap->getKey = eap_psk_getKey;
+       eap->getSessionId = eap_psk_get_session_id;
        eap->get_emsk = eap_psk_get_emsk;
 
        ret = eap_peer_method_register(eap);
index 1957c82..267d0a5 100644 (file)
@@ -2,19 +2,14 @@
  * EAP peer method: EAP-pwd (RFC 5931)
  * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD license.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * See README and COPYING for more details.
+ * 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"
 
@@ -32,6 +27,12 @@ struct eap_pwd_data {
        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;
@@ -69,7 +70,7 @@ static const char * eap_pwd_state_txt(int state)
 
 static void eap_pwd_state(struct eap_pwd_data *data, int state)
 {
-       wpa_printf(MSG_INFO, "EAP-PWD: %s -> %s",
+       wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s",
                   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
        data->state = state;
 }
@@ -124,6 +125,10 @@ static void * eap_pwd_init(struct eap_sm *sm)
        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;
@@ -174,23 +179,24 @@ static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
-static struct wpabuf *
+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;
-       struct wpabuf *resp;
 
        if (data->state != PWD_ID_Req) {
                ret->ignore = TRUE;
-               return NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
        }
 
        if (payload_len < sizeof(struct eap_pwd_id)) {
                ret->ignore = TRUE;
-               return NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
        }
 
        id = (struct eap_pwd_id *) payload;
@@ -198,16 +204,18 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
            (id->prf != EAP_PWD_DEFAULT_PRF)) {
                ret->ignore = TRUE;
-               return NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
        }
 
-       wpa_printf(MSG_DEBUG, "EAP-PWD (peer): server said group %d",
+       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");
-               return NULL;
+               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);
@@ -218,7 +226,8 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
            NULL) {
                wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
                           "group");
-               return NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
        }
 
        /* compute PWE */
@@ -228,39 +237,36 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
                                     data->id_peer, data->id_peer_len,
                                     id->token)) {
                wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
-               return NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
        }
 
-       wpa_printf(MSG_INFO, "EAP-PWD (peer): computed %d bit PWE...",
+       wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
                   BN_num_bits(data->grp->prime));
 
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                            1 + sizeof(struct eap_pwd_id) + data->id_peer_len,
-                            EAP_CODE_RESPONSE, eap_get_id(reqData));
-       if (resp == NULL)
-               return NULL;
-
-       wpabuf_put_u8(resp, EAP_PWD_OPCODE_ID_EXCH);
-       wpabuf_put_be16(resp, data->group_num);
-       wpabuf_put_u8(resp, EAP_PWD_DEFAULT_RAND_FUNC);
-       wpabuf_put_u8(resp, EAP_PWD_DEFAULT_PRF);
-       wpabuf_put_data(resp, id->token, sizeof(id->token));
-       wpabuf_put_u8(resp, EAP_PWD_PREP_NONE);
-       wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
+       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);
-
-       return resp;
 }
 
 
-static struct wpabuf *
+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)
 {
-       struct wpabuf *resp = NULL;
        EC_POINT *K = NULL, *point = NULL;
        BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
        u16 offset;
@@ -422,18 +428,15 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                            1 + BN_num_bytes(data->grp->order) +
-                            (2 * BN_num_bytes(data->grp->prime)),
-                            EAP_CODE_RESPONSE, eap_get_id(reqData));
-       if (resp == NULL)
+       data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) +
+                                   2 * BN_num_bytes(data->grp->prime));
+       if (data->outbuf == NULL)
                goto fin;
 
-       wpabuf_put_u8(resp, EAP_PWD_OPCODE_COMMIT_EXCH);
-
        /* we send the element as (x,y) follwed by the scalar */
-       wpabuf_put_data(resp, element, (2 * BN_num_bytes(data->grp->prime)));
-       wpabuf_put_data(resp, scalar, BN_num_bytes(data->grp->order));
+       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);
@@ -443,27 +446,24 @@ fin:
        BN_free(cofactor);
        EC_POINT_free(K);
        EC_POINT_free(point);
-       if (resp == NULL)
+       if (data->outbuf == NULL)
                eap_pwd_state(data, FAILURE);
        else
                eap_pwd_state(data, PWD_Confirm_Req);
-
-       return resp;
 }
 
 
-static struct wpabuf *
+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)
 {
-       struct wpabuf *resp = NULL;
        BIGNUM *x = NULL, *y = NULL;
-       HMAC_CTX ctx;
+       struct crypto_hash *hash;
        u32 cs;
        u16 grp;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
        int offset;
 
        /*
@@ -481,7 +481,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        /* 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 "
+               wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
                           "fail");
                goto fin;
        }
@@ -490,7 +490,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
         * server's commit is H(k | server_element | server_scalar |
         *                      peer_element | peer_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /*
         * zero the memory each time because this is mod prime math and some
@@ -499,7 +501,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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,
@@ -512,18 +514,18 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       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,
@@ -537,27 +539,27 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* the ciphersuite */
-       H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* random function fin */
-       H_Final(&ctx, conf);
+       eap_pwd_h_final(hash, conf);
 
        ptr = (u8 *) payload;
-       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+       if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
                wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
                goto fin;
        }
@@ -569,13 +571,15 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
         *  H(k | peer_element | peer_scalar | server_element | server_scalar |
         *    ciphersuite)
         */
-       H_Init(&ctx);
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* my element */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -588,18 +592,18 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       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,
@@ -612,33 +616,24 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* the ciphersuite */
-       H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* all done */
-       H_Final(&ctx, conf);
-
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                            1 + SHA256_DIGEST_LENGTH,
-                            EAP_CODE_RESPONSE, eap_get_id(reqData));
-       if (resp == NULL)
-               goto fin;
-
-       wpabuf_put_u8(resp, EAP_PWD_OPCODE_CONFIRM_EXCH);
-       wpabuf_put_data(resp, conf, SHA256_DIGEST_LENGTH);
+       eap_pwd_h_final(hash, conf);
 
        if (compute_keys(data->grp, data->bnctx, data->k,
                         data->my_scalar, data->server_scalar, conf, ptr,
@@ -648,20 +643,24 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
                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 (resp == NULL) {
+       if (data->outbuf == NULL) {
                ret->decision = DECISION_FAIL;
                eap_pwd_state(data, FAILURE);
        } else {
                ret->decision = DECISION_UNCOND_SUCC;
                eap_pwd_state(data, SUCCESS);
        }
-
-       return resp;
 }
 
 
@@ -671,42 +670,203 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
 {
        struct eap_pwd_data *data = priv;
        struct wpabuf *resp = NULL;
-       const u8 *pos;
+       const u8 *pos, *buf;
        size_t len;
-       u8 exch;
+       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;
        }
 
-       wpa_printf(MSG_INFO, "EAP-pwd: Received frame: opcode %d", *pos);
-
        ret->ignore = FALSE;
        ret->methodState = METHOD_MAY_CONT;
        ret->decision = DECISION_FAIL;
        ret->allowNotifications = FALSE;
 
-       exch = *pos & 0x3f;
-       switch (exch) {
-        case EAP_PWD_OPCODE_ID_EXCH:
-               resp = eap_pwd_perform_id_exchange(sm, data, ret, reqData,
-                                                  pos + 1, len - 1);
+       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:
-               resp = eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
-                                                      pos + 1, len - 1);
+       case EAP_PWD_OPCODE_COMMIT_EXCH:
+               eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
+                                               pos, len);
                break;
-        case EAP_PWD_OPCODE_CONFIRM_EXCH:
-               resp = eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
-                                                       pos + 1, len - 1);
+       case EAP_PWD_OPCODE_CONFIRM_EXCH:
+               eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
+                                                pos, len);
                break;
-        default:
+       default:
                wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
-                          "opcode %d", exch);
+                          "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;
 }
index 1474b7f..431519c 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-SAKE (RFC 4763)
  * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -458,6 +452,28 @@ static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_sake_data *data = priv;
+       u8 *id;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+       id = os_malloc(*len);
+       if (id == NULL)
+               return NULL;
+
+       id[0] = EAP_TYPE_SAKE;
+       os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+       os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+       wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+       return id;
+}
+
+
 static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_sake_data *data = priv;
@@ -491,6 +507,7 @@ int eap_peer_sake_register(void)
        eap->process = eap_sake_process;
        eap->isKeyAvailable = eap_sake_isKeyAvailable;
        eap->getKey = eap_sake_getKey;
+       eap->getSessionId = eap_sake_get_session_id;
        eap->get_emsk = eap_sake_get_emsk;
 
        ret = eap_peer_method_register(eap);
index 06fbc5b..82ea18d 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer method: EAP-SIM (RFC 4186)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -123,6 +117,15 @@ static void * eap_sim_init(struct eap_sm *sm)
                        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;
@@ -264,13 +267,15 @@ static int eap_sim_supported_ver(int version)
 #define CLEAR_REAUTH_ID        0x02
 #define CLEAR_EAP_ID   0x04
 
-static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
+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");
@@ -287,24 +292,45 @@ static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
 }
 
 
-static int eap_sim_learn_ids(struct eap_sim_data *data,
+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);
-               data->pseudonym = os_malloc(attr->next_pseudonym_len);
+               /* 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);
-               data->pseudonym_len = attr->next_pseudonym_len;
-               wpa_hexdump_ascii(MSG_DEBUG,
-                                 "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
-                                 data->pseudonym,
-                                 data->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) {
@@ -313,6 +339,7 @@ static int eap_sim_learn_ids(struct eap_sim_data *data,
                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,
@@ -337,6 +364,8 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
        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);
@@ -361,16 +390,16 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
                   data->pseudonym) {
                identity = data->pseudonym;
                identity_len = data->pseudonym_len;
-               eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
+               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(data, CLEAR_PSEUDONYM |
+                       eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
                                                 CLEAR_REAUTH_ID);
                }
        }
        if (id_req != NO_ID_REQ)
-               eap_sim_clear_identities(data, CLEAR_EAP_ID);
+               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,
@@ -417,7 +446,8 @@ static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
 
 
 static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
-                                              u8 id, int counter_too_small)
+                                              u8 id, int counter_too_small,
+                                              const u8 *nonce_s)
 {
        struct eap_sim_msg *msg;
        unsigned int counter;
@@ -452,7 +482,7 @@ static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
        }
        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,
+       return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
                                  EAP_SIM_NONCE_S_LEN);
 }
 
@@ -652,7 +682,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
         * 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(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+       eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
        if (attr->encr_data) {
                u8 *decrypted;
@@ -663,7 +693,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
                        return eap_sim_client_error(
                                data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
                }
-               eap_sim_learn_ids(data, &eattr);
+               eap_sim_learn_ids(sm, data, &eattr);
                os_free(decrypted);
        }
 
@@ -848,7 +878,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
                data->reauth_id = NULL;
                data->reauth_id_len = 0;
                os_free(decrypted);
-               return eap_sim_response_reauth(data, id, 1);
+               return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
        }
        data->counter = eattr.counter;
 
@@ -860,8 +890,8 @@ static struct wpabuf * eap_sim_process_reauthentication(
                                   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);
+       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;
@@ -876,10 +906,11 @@ static struct wpabuf * eap_sim_process_reauthentication(
        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);
+               eap_sim_clear_identities(sm, data,
+                                        CLEAR_REAUTH_ID | CLEAR_EAP_ID);
        }
        os_free(decrypted);
-       return eap_sim_response_reauth(data, id, 0);
+       return eap_sim_response_reauth(data, id, 0, data->nonce_s);
 }
 
 
@@ -987,7 +1018,7 @@ static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
 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);
+       eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
        data->use_result_ind = 0;
 }
 
@@ -1053,6 +1084,29 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_sim_data *data = priv;
+       u8 *id;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+       id = os_malloc(*len);
+       if (id == NULL)
+               return NULL;
+
+       id[0] = EAP_TYPE_SIM;
+       os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+       os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+                 EAP_SIM_NONCE_MT_LEN);
+       wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+       return id;
+}
+
+
 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_sim_data *data = priv;
@@ -1087,6 +1141,7 @@ int eap_peer_sim_register(void)
        eap->process = eap_sim_process;
        eap->isKeyAvailable = eap_sim_isKeyAvailable;
        eap->getKey = eap_sim_getKey;
+       eap->getSessionId = eap_sim_get_session_id;
        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;
index 20b2212..d2066cd 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -27,6 +21,10 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
 struct eap_tls_data {
        struct eap_ssl_data ssl;
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
+       void *ssl_ctx;
+       u8 eap_type;
 };
 
 
@@ -46,7 +44,10 @@ static void * eap_tls_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
 
-       if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+       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) {
@@ -64,10 +65,39 @@ static void * eap_tls_init(struct eap_sm *sm)
                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;
@@ -75,6 +105,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
                return;
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        os_free(data);
 }
 
@@ -111,7 +142,7 @@ static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
                return resp;
        }
 
-       return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
+       return eap_peer_tls_build_ack(id, data->eap_type, 0);
 }
 
 
@@ -137,6 +168,17 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
        } else {
                wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
        }
+
+       os_free(data->session_id);
+       data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                         EAP_TYPE_TLS,
+                                                         &data->id_len);
+       if (data->session_id) {
+               wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
+                           data->session_id, data->id_len);
+       } else {
+               wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
+       }
 }
 
 
@@ -151,7 +193,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
        const u8 *pos;
        struct eap_tls_data *data = priv;
 
-       pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
+       pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
                                        reqData, &left, &flags);
        if (pos == NULL)
                return NULL;
@@ -164,19 +206,19 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
        }
 
        resp = NULL;
-       res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
-                                         pos, left, &resp);
+       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(sm->ssl_ctx, data->ssl.conn))
+       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, EAP_TYPE_TLS, 0);
+               return eap_peer_tls_build_ack(id, data->eap_type, 0);
        }
 
        return resp;
@@ -186,7 +228,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
 {
        struct eap_tls_data *data = priv;
-       return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+       return tls_connection_established(data->ssl_ctx, data->ssl.conn);
 }
 
 
@@ -200,6 +242,8 @@ 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;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -261,6 +305,25 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_tls_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_tls_register(void)
 {
        struct eap_method *eap;
@@ -276,6 +339,37 @@ int eap_peer_tls_register(void)
        eap->process = eap_tls_process;
        eap->isKeyAvailable = eap_tls_isKeyAvailable;
        eap->getKey = eap_tls_getKey;
+       eap->getSessionId = eap_tls_get_session_id;
+       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;
@@ -287,3 +381,4 @@ int eap_peer_tls_register(void)
                eap_peer_method_free(eap);
        return ret;
 }
+#endif /* EAP_UNAUTH_TLS */
index 2934ba4..be8c301 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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)
 {
@@ -54,6 +60,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
                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;
 }
 
 
@@ -105,6 +115,18 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
                                    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);
@@ -142,14 +164,18 @@ static int eap_tls_init_connection(struct eap_sm *sm,
 {
        int res;
 
-       data->conn = tls_connection_init(sm->ssl_ctx);
+       if (config->ocsp)
+               params->flags |= TLS_CONN_REQUEST_OCSP;
+       if (config->ocsp == 2)
+               params->flags |= TLS_CONN_REQUIRE_OCSP;
+       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(sm->ssl_ctx, data->conn, params);
+       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.
@@ -168,13 +194,13 @@ static int eap_tls_init_connection(struct eap_sm *sm,
                config->pin = NULL;
                eap_sm_request_pin(sm);
                sm->ignore = TRUE;
-               tls_connection_deinit(sm->ssl_ctx, data->conn);
+               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(sm->ssl_ctx, data->conn);
+               tls_connection_deinit(data->ssl_ctx, data->conn);
                data->conn = NULL;
                return -1;
        }
@@ -188,13 +214,14 @@ static int eap_tls_init_connection(struct eap_sm *sm,
  * @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)
+                         struct eap_peer_config *config, u8 eap_type)
 {
        struct tls_connection_params params;
 
@@ -202,7 +229,10 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
                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;
@@ -240,7 +270,7 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
  */
 void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 {
-       tls_connection_deinit(sm->ssl_ctx, data->conn);
+       tls_connection_deinit(data->ssl_ctx, data->conn);
        eap_peer_tls_reset_input(data);
        eap_peer_tls_reset_output(data);
 }
@@ -263,7 +293,9 @@ 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)
 {
+#ifndef CONFIG_FIPS
        struct tls_keys keys;
+#endif /* CONFIG_FIPS */
        u8 *rnd = NULL, *out;
 
        out = os_malloc(len);
@@ -271,16 +303,17 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
                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)
+       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(sm->ssl_ctx, data->conn, &keys))
+       if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
                goto fail;
 
        if (keys.client_random == NULL || keys.server_random == NULL ||
@@ -303,6 +336,7 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        return out;
 
 fail:
+#endif /* CONFIG_FIPS */
        os_free(out);
        os_free(rnd);
        return NULL;
@@ -310,6 +344,52 @@ fail:
 
 
 /**
+ * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+                                   struct eap_ssl_data *data, u8 eap_type,
+                                   size_t *len)
+{
+       struct tls_keys keys;
+       u8 *out;
+
+       /*
+        * TLS library did not support session ID generation,
+        * so get the needed TLS session parameters
+        */
+       if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+               return NULL;
+
+       if (keys.client_random == NULL || keys.server_random == NULL ||
+           keys.master_key == NULL)
+               return NULL;
+
+       *len = 1 + keys.client_random_len + keys.server_random_len;
+       out = os_malloc(*len);
+       if (out == NULL)
+               return NULL;
+
+       /* Session-Id = EAP type || client.random || server.random */
+       out[0] = eap_type;
+       os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+       os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+                 keys.server_random_len);
+
+       return out;
+}
+
+
+/**
  * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
  * @data: Data for TLS processing
  * @in_data: Next incoming TLS segment
@@ -447,14 +527,14 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
                WPA_ASSERT(data->tls_out == NULL);
        }
        appl_data = NULL;
-       data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
+       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(sm->ssl_ctx, data->conn) &&
-           !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+           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;
@@ -520,9 +600,8 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
                length_included = 1;
        }
 
-       *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
-                                 1 + length_included * 4 + len,
-                                 EAP_CODE_RESPONSE, id);
+       *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
+                                     EAP_CODE_RESPONSE, id);
        if (*out_data == NULL)
                return -1;
 
@@ -622,7 +701,7 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
                return -1;
        }
 
-       if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+       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");
@@ -660,8 +739,7 @@ struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
 {
        struct wpabuf *resp;
 
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE,
-                            id);
+       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)",
@@ -681,7 +759,7 @@ 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);
+       return tls_connection_shutdown(data->ssl_ctx, data->conn);
 }
 
 
@@ -700,7 +778,8 @@ int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
        char name[128];
        int len = 0, ret;
 
-       if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
+       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)
@@ -747,13 +826,19 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
        size_t left;
        unsigned int tls_msg_len;
 
-       if (tls_get_errors(sm->ssl_ctx)) {
+       if (tls_get_errors(data->ssl_ctx)) {
                wpa_printf(MSG_INFO, "SSL: TLS errors detected");
                ret->ignore = TRUE;
                return NULL;
        }
 
-       pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left);
+       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;
@@ -794,6 +879,14 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
                }
                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;
@@ -855,7 +948,7 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
        if (msg == NULL)
                return need_more_input ? 1 : -1;
 
-       *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg);
+       *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");
@@ -883,8 +976,8 @@ int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 {
        if (in_data) {
                eap_peer_tls_reset_output(data);
-               data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn,
-                                                      in_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)",
@@ -949,8 +1042,8 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config,
                                   "method '%s'", start);
                } else {
                        num_methods++;
-                       _methods = os_realloc(methods,
-                                             num_methods * sizeof(*methods));
+                       _methods = os_realloc_array(methods, num_methods,
+                                                   sizeof(*methods));
                        if (_methods == NULL) {
                                os_free(methods);
                                os_free(buf);
index e9a07b8..1a5e0f8 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_TLS_COMMON_H
@@ -69,6 +63,16 @@ struct eap_ssl_data {
         * 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;
 };
 
 
@@ -81,12 +85,18 @@ struct eap_ssl_data {
  /* 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);
+                         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);
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+                                   struct eap_ssl_data *data, u8 eap_type,
+                                   size_t *len);
 int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
                                EapType eap_type, int peap_version,
                                u8 id, const u8 *in_data, size_t in_len,
index da288eb..bc13647 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-TNC (Trusted Network Connect)
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 612dfa7..5091bf0 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: EAP-TTLS (RFC 5281)
  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -60,6 +54,8 @@ struct eap_ttls_data {
        int resuming; /* starting a resumed session */
        int reauth; /* reauthentication */
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
 
        struct wpabuf *pending_phase2_req;
 
@@ -116,7 +112,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
                data->phase2_eap_type.method = EAP_TYPE_NONE;
        }
 
-       if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+       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;
@@ -146,6 +142,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
        os_free(data->phase2_eap_types);
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -228,6 +225,17 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
        wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
                        data->key_data, EAP_TLS_KEY_LEN);
 
+       os_free(data->session_id);
+       data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                         EAP_TYPE_TTLS,
+                                                         &data->id_len);
+       if (data->session_id) {
+               wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+                           data->session_id, data->id_len);
+       } else {
+               wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
+       }
+
        return 0;
 }
 
@@ -407,6 +415,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                                            struct eap_method_ret *ret,
                                            struct wpabuf **resp)
 {
+#ifdef EAP_MSCHAPv2
        struct wpabuf *msg;
        u8 *buf, *pos, *challenge, *peer_challenge;
        const u8 *identity, *password;
@@ -441,7 +450,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                           "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,
@@ -454,7 +462,14 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
        data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
        *pos++ = data->ident;
        *pos++ = 0; /* Flags */
-       os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+       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;
@@ -462,6 +477,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                                     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");
@@ -487,6 +503,10 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
        }
 
        return 0;
+#else /* EAP_MSCHAPv2 */
+       wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+       return -1;
+#endif /* EAP_MSCHAPv2 */
 }
 
 
@@ -1041,6 +1061,7 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
                                            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");
@@ -1089,6 +1110,10 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
         * 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 */
 }
 
 
@@ -1517,6 +1542,8 @@ 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;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -1601,6 +1628,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_ttls_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL || !data->phase2_success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_ttls_register(void)
 {
        struct eap_method *eap;
@@ -1616,6 +1662,7 @@ int eap_peer_ttls_register(void)
        eap->process = eap_ttls_process;
        eap->isKeyAvailable = eap_ttls_isKeyAvailable;
        eap->getKey = eap_ttls_getKey;
+       eap->getSessionId = eap_ttls_get_session_id;
        eap->get_status = eap_ttls_get_status;
        eap->has_reauth_data = eap_ttls_has_reauth_data;
        eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
index 3e114c1..040d1e7 100644 (file)
@@ -2,14 +2,8 @@
  * EAP peer method: Test method for vendor specific (expanded) EAP type
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -25,7 +19,7 @@
 #endif /* TEST_PENDING_REQUEST */
 
 
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
 #define EAP_VENDOR_TYPE 0xfcfbfaf9
 
 
index 09d8a1c..8edb1ca 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -83,25 +77,33 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
        else
                len = end - pos;
        if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
-           hexstr2bin(pos, cred->ssid, len / 2))
+           hexstr2bin(pos, cred->ssid, len / 2)) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
                return -1;
+       }
        cred->ssid_len = len / 2;
 
        pos = os_strstr(params, "new_auth=");
-       if (pos == NULL)
+       if (pos == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
                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
+       else {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
                return -1;
+       }
 
        pos = os_strstr(params, "new_encr=");
-       if (pos == NULL)
+       if (pos == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
                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)
@@ -110,8 +112,10 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
                cred->encr_type = WPS_ENCR_TKIP;
        else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
                cred->encr_type = WPS_ENCR_AES;
-       else
+       else {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
                return -1;
+       }
 
        pos = os_strstr(params, "new_key=");
        if (pos == NULL)
@@ -123,8 +127,10 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
        else
                len = end - pos;
        if ((len & 1) || len > 2 * sizeof(cred->key) ||
-           hexstr2bin(pos, cred->key, len / 2))
+           hexstr2bin(pos, cred->key, len / 2)) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
                return -1;
+       }
        cred->key_len = len / 2;
 
        return 1;
@@ -143,6 +149,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
        struct wps_context *wps;
        struct wps_credential new_ap_settings;
        int res;
+       int nfc = 0;
 
        wps = sm->wps;
        if (wps == NULL) {
@@ -190,13 +197,19 @@ static void * eap_wsc_init(struct eap_sm *sm)
                while (*pos != '\0' && *pos != ' ')
                        pos++;
                cfg.pin_len = pos - (const char *) cfg.pin;
+               if (cfg.pin_len == 6 &&
+                   os_strncmp((const char *) cfg.pin, "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) {
+       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);
@@ -210,6 +223,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
        res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
        if (res < 0) {
                os_free(data);
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+                          "settings");
                return NULL;
        }
        if (res == 1) {
@@ -221,6 +236,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
        data->wps = wps_init(&cfg);
        if (data->wps == NULL) {
                os_free(data);
+               wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
                return NULL;
        }
        res = eap_get_config_fragment_size(sm);
index acd7611..fcf4712 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 responder (RFC 4306) for EAP-IKEV2
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 9ca0ca5..627a2cb 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 responder (RFC 4306) for EAP-IKEV2
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IKEV2_H
index b8fb075..37e6735 100644 (file)
@@ -2,14 +2,8 @@
  * MSCHAPV2 (RFC 2759)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -69,22 +63,28 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
        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);
+               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);
-               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);
+               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);
@@ -100,7 +100,8 @@ int mschapv2_derive_response(const u8 *identity, size_t identity_len,
                    hash_nt_password_hash(password_hash, password_hash_hash))
                        return -1;
        }
-       get_master_key(password_hash_hash, nt_response, master_key);
+       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);
 
index 90dad31..edd458b 100644 (file)
@@ -2,14 +2,8 @@
  * MSCHAPV2 (RFC 2759)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef MSCHAPV2_H
index a70d70c..a3ec395 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -747,12 +741,10 @@ enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
        enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
        int recommendation_msg = 0;
 
-       buf = os_malloc(len + 1);
+       buf = dup_binstr(msg, len);
        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) {
index 4d42a05..df2a287 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TNCC_H
index d5f8f1d..f2a7cd7 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP Full Authenticator state machine (RFC 4137)
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_H
index f48cf71..f92704a 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP Authenticator state machine internal structures (RFC 4137)
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_I_H
@@ -157,7 +151,7 @@ struct eap_sm {
        int user_eap_method_index;
        int init_phase2;
        void *ssl_ctx;
-       void *eap_sim_db_priv;
+       struct eap_sim_db_data *eap_sim_db_priv;
        Boolean backend_auth;
        Boolean update_user;
        int eap_server;
index 4a5296e..bc810a9 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server method registration
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_SERVER_METHODS_H
@@ -32,6 +26,7 @@ const char * eap_server_get_name(int vendor, EapType type);
 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);
index 7a5beb6..15f7e22 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP Full Authenticator state machine (RFC 4137)
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -281,6 +275,11 @@ 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);
@@ -315,6 +314,9 @@ 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);
@@ -386,6 +388,9 @@ SM_STATE(EAP, NAK)
        }
        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);
index 0f25ffd..469b9a0 100644 (file)
@@ -1,15 +1,9 @@
 /*
- * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -55,12 +49,12 @@ struct eap_aka_data {
        u8 *network_name;
        size_t network_name_len;
        u16 kdf;
+       int identity_round;
+       char permanent[20]; /* Permanent username */
 };
 
 
-static void eap_aka_determine_identity(struct eap_sm *sm,
-                                      struct eap_aka_data *data,
-                                      int before_identity, int after_reauth);
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
 
 
 static const char * eap_aka_state_txt(int state)
@@ -93,6 +87,96 @@ static void eap_aka_state(struct eap_aka_data *data, int 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;
@@ -109,8 +193,8 @@ static void * eap_aka_init(struct eap_sm *sm)
        data->eap_method = EAP_TYPE_AKA;
 
        data->state = IDENTITY;
-       eap_aka_determine_identity(sm, data, 1, 0);
        data->pending_id = -1;
+       eap_aka_check_identity(sm, data);
 
        return data;
 }
@@ -142,8 +226,8 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
        data->network_name_len = os_strlen(network_name);
 
        data->state = IDENTITY;
-       eap_aka_determine_identity(sm, data, 1, 0);
        data->pending_id = -1;
+       eap_aka_check_identity(sm, data);
 
        return data;
 }
@@ -270,11 +354,8 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
        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 {
+       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
@@ -282,6 +363,19 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
                 */
                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) {
@@ -298,12 +392,23 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
                              const u8 *nonce_s)
 {
        os_free(data->next_pseudonym);
-       data->next_pseudonym =
-               eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
+       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, 1);
+                       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");
@@ -607,92 +712,83 @@ static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
 
 
 static void eap_aka_determine_identity(struct eap_sm *sm,
-                                      struct eap_aka_data *data,
-                                      int before_identity, int after_reauth)
+                                      struct eap_aka_data *data)
 {
-       const u8 *identity;
-       size_t identity_len;
-       int res;
+       char *username;
 
-       identity = NULL;
-       identity_len = 0;
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
+                         sm->identity, sm->identity_len);
 
-       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);
-                               }
-                       }
-               }
+       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 (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. */
-               }
+       if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+               os_free(username);
+               return;
        }
 
-       wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
-                         identity, identity_len);
+       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 (!after_reauth && data->reauth) {
-               eap_aka_state(data, REAUTH);
+       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;
        }
 
-       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);
+       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");
@@ -737,7 +833,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
                          sm->identity, identity_len);
 
        if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-               eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+               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 {
@@ -756,6 +852,8 @@ static void eap_aka_process_identity(struct eap_sm *sm,
                                     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) {
@@ -766,17 +864,30 @@ static void eap_aka_process_identity(struct eap_sm *sm,
                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;
-               }
+       /*
+        * 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, 0, 0);
+       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);
@@ -801,9 +912,6 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
                                      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
@@ -876,16 +984,8 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
        } 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,
+               eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
                                         data->next_pseudonym);
                data->next_pseudonym = NULL;
        }
@@ -893,16 +993,15 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
                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->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, identity,
-                                             identity_len,
+                       eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+                                             data->permanent,
                                              data->next_reauth_id,
                                              data->counter + 1,
                                              data->mk);
@@ -931,9 +1030,8 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
         * maintaining a local flag stating whether this AUTS has already been
         * reported. */
        if (!data->auts_reported &&
-           eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
-                                    sm->identity_len, attr->auts,
-                                    data->rand)) {
+           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);
@@ -941,8 +1039,7 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
        }
        data->auts_reported = 1;
 
-       /* Try again after resynchronization */
-       eap_aka_determine_identity(sm, data, 0, 0);
+       /* Remain in CHALLENGE state to re-try after resynchronization */
 }
 
 
@@ -953,8 +1050,6 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
 {
        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");
 
@@ -997,7 +1092,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
                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);
+               eap_aka_fullauth(sm, data);
                return;
        }
 
@@ -1008,40 +1103,19 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
        } 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->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, identity,
-                                             identity_len,
+                       eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+                                             data->permanent,
                                              data->next_reauth_id,
                                              data->counter + 1,
                                              data->mk);
index ba17e98..fcb80dc 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-FAST server (RFC 4851)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index a794806..2853c48 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-GPSK (RFC 5433) server
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 79b9696..f423106 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-GTC (RFC 3748)
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index cd8da2a..51dc4e8 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-Identity
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index ec4fa87..42aaca2 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-IKEv2 server (RFC 5106)
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index d03ec53..5a5e290 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / EAP-MD5 server
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -125,8 +119,12 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
        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 (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");
index 4d241a4..0209fad 100644 (file)
@@ -2,14 +2,8 @@
  * EAP server method registration
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f5ee7f4..8d3dd52 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 4d64269..35a42ad 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-PAX (RFC 4746) server
  * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 50e79c0..68253c4 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index fb299ae..0cd9799 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-PSK (RFC 4764) server
  * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
index 4c6f4d1..b61061b 100644 (file)
@@ -2,19 +2,14 @@
  * hostapd / EAP-pwd (RFC 5931) server
  * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD license.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * See README and COPYING for more details.
+ * 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"
 
@@ -33,6 +28,12 @@ struct eap_pwd_data {
        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;
@@ -40,7 +41,7 @@ struct eap_pwd_data {
        EC_POINT *my_element;
        EC_POINT *peer_element;
 
-       u8 my_confirm[SHA256_DIGEST_LENGTH];
+       u8 my_confirm[SHA256_MAC_LEN];
 
        u8 msk[EAP_MSK_LEN];
        u8 emsk[EAP_EMSK_LEN];
@@ -120,6 +121,10 @@ static void * eap_pwd_init(struct eap_sm *sm)
                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;
 }
 
@@ -149,44 +154,48 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv)
 }
 
 
-static struct wpabuf *
-eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
+static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
+                                u8 id)
 {
-       struct wpabuf *req;
-
        wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                           1 + sizeof(struct eap_pwd_id) +
-                           data->id_server_len,
-                           EAP_CODE_REQUEST, id);
-       if (req == NULL) {
+       /*
+        * 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 NULL;
+               return;
        }
 
        /* an lfsr is good enough to generate unpredictable tokens */
        data->token = os_random();
-       wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
-       wpabuf_put_be16(req, data->group_num);
-       wpabuf_put_u8(req, EAP_PWD_DEFAULT_RAND_FUNC);
-       wpabuf_put_u8(req, EAP_PWD_DEFAULT_PRF);
-       wpabuf_put_data(req, &data->token, sizeof(data->token));
-       wpabuf_put_u8(req, EAP_PWD_PREP_NONE);
-       wpabuf_put_data(req, data->id_server, data->id_server_len);
-
-       return req;
+       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 struct wpabuf *
-eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
+static void eap_pwd_build_commit_req(struct eap_sm *sm,
+                                    struct eap_pwd_data *data, u8 id)
 {
-       struct wpabuf *req = NULL;
        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) ||
@@ -256,41 +265,42 @@ eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                           1 + (2 * BN_num_bytes(data->grp->prime)) +
-                           BN_num_bytes(data->grp->order),
-                           EAP_CODE_REQUEST, id);
-       if (req == NULL)
+       data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
+                                   BN_num_bytes(data->grp->order));
+       if (data->outbuf == NULL)
                goto fin;
-       wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
 
        /* We send the element as (x,y) followed by the scalar */
-       wpabuf_put_data(req, element, (2 * BN_num_bytes(data->grp->prime)));
-       wpabuf_put_data(req, scalar, BN_num_bytes(data->grp->order));
+       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 (req == NULL)
+       if (data->outbuf == NULL)
                eap_pwd_state(data, FAILURE);
-
-       return req;
 }
 
 
-static struct wpabuf *
-eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
+static void eap_pwd_build_confirm_req(struct eap_sm *sm,
+                                     struct eap_pwd_data *data, u8 id)
 {
-       struct wpabuf *req = NULL;
        BIGNUM *x = NULL, *y = NULL;
-       HMAC_CTX ctx;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       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) ||
@@ -304,7 +314,9 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
         * commit is H(k | server_element | server_scalar | peer_element |
         *             peer_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /*
         * Zero the memory each time because this is mod prime math and some
@@ -315,7 +327,7 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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,
@@ -329,18 +341,18 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       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,
@@ -354,18 +366,18 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* ciphersuite */
        grp = htons(data->group_num);
@@ -377,29 +389,24 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
        ptr += sizeof(u8);
        *ptr = EAP_PWD_DEFAULT_PRF;
        ptr += sizeof(u8);
-       H_Update(&ctx, cruft, ptr-cruft);
+       eap_pwd_h_update(hash, cruft, ptr - cruft);
 
        /* all done with the random function */
-       H_Final(&ctx, conf);
-       os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
+       eap_pwd_h_final(hash, conf);
+       os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
 
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-                           1 + SHA256_DIGEST_LENGTH,
-                           EAP_CODE_REQUEST, id);
-       if (req == NULL)
+       data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
+       if (data->outbuf == NULL)
                goto fin;
 
-       wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
-       wpabuf_put_data(req, conf, SHA256_DIGEST_LENGTH);
+       wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
        os_free(cruft);
        BN_free(x);
        BN_free(y);
-       if (req == NULL)
+       if (data->outbuf == NULL)
                eap_pwd_state(data, FAILURE);
-
-       return req;
 }
 
 
@@ -407,21 +414,119 @@ 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:
-               return eap_pwd_build_id_req(sm, data, id);
-        case PWD_Commit_Req:
-               return eap_pwd_build_commit_req(sm, data, id);
-        case PWD_Confirm_Req:
-               return eap_pwd_build_confirm_req(sm, data, id);
-        default:
+       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;
        }
 
-       return NULL;
+       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;
 }
 
 
@@ -438,17 +543,19 @@ static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
                return TRUE;
        }
 
-       wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: opcode=%d", *pos);
+       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 && *pos == EAP_PWD_OPCODE_ID_EXCH)
+       if (data->state == PWD_ID_Req &&
+           ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
                return FALSE;
 
        if (data->state == PWD_Commit_Req &&
-           *pos == EAP_PWD_OPCODE_COMMIT_EXCH)
+           ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
                return FALSE;
 
        if (data->state == PWD_Confirm_Req &&
-           *pos == EAP_PWD_OPCODE_CONFIRM_EXCH)
+           ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
                return FALSE;
 
        wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
@@ -629,10 +736,10 @@ 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;
-       HMAC_CTX ctx;
+       struct crypto_hash *hash;
        u32 cs;
        u16 grp;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
        int offset;
 
        /* build up the ciphersuite: group | random_function | prf */
@@ -655,13 +762,15 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
         * commit is H(k | peer_element | peer_scalar | server_element |
         *             server_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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,
@@ -674,18 +783,18 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       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,
@@ -699,28 +808,28 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
        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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       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);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* ciphersuite */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-       H_Update(&ctx, (u8 *)&cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* all done */
-       H_Final(&ctx, conf);
+       eap_pwd_h_final(hash, conf);
 
        ptr = (u8 *) payload;
-       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+       if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
                wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
                           "verify");
                goto fin;
@@ -747,7 +856,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
        struct eap_pwd_data *data = priv;
        const u8 *pos;
        size_t len;
-       u8 exch;
+       u8 lm_exch;
+       u16 tot_len;
 
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
        if ((pos == NULL) || (len < 1)) {
@@ -757,18 +867,90 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
                return;
        }
 
-       exch = *pos & 0x3f;
-       switch (exch) {
+       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 + 1, len - 1);
+               eap_pwd_process_id_resp(sm, data, pos, len);
                break;
        case EAP_PWD_OPCODE_COMMIT_EXCH:
-               eap_pwd_process_commit_resp(sm, data, pos + 1, len - 1);
+               eap_pwd_process_commit_resp(sm, data, pos, len);
                break;
-        case EAP_PWD_OPCODE_CONFIRM_EXCH:
-               eap_pwd_process_confirm_resp(sm, data, pos + 1, len - 1);
+       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;
+       }
 }
 
 
index a9b515f..f72e1bf 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-SAKE (RFC 4763) server
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 29df2ff..b531241 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / EAP-SIM (RFC 4186)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -42,6 +36,8 @@ struct eap_sim_data {
        struct eap_sim_reauth *reauth;
        u16 notification;
        int use_result_ind;
+       int start_round;
+       char permanent[20]; /* Permanent username */
 };
 
 
@@ -111,17 +107,33 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
        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 {
+       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;
@@ -137,12 +149,19 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
                              const u8 *nonce_s)
 {
        os_free(data->next_pseudonym);
-       data->next_pseudonym =
-               eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
+       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, 0);
+                       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");
@@ -327,18 +346,22 @@ static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
 static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
                             struct wpabuf *respData)
 {
-       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;
 
+       return FALSE;
+}
+
+
+static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
+                                         u8 subtype)
+{
        if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
                return FALSE;
 
@@ -392,85 +415,113 @@ static void eap_sim_process_start(struct eap_sm *sm,
                                  struct wpabuf *respData,
                                  struct eap_sim_attrs *attr)
 {
-       const u8 *identity;
        size_t identity_len;
        u8 ver_list[2];
+       u8 *new_identity;
+       char *username;
 
        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;
-               }
+       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;
        }
 
-       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);
-                       }
-               }
+       /*
+        * 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;
        }
 
-       if (identity == NULL) {
-               wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
-                          " user name");
-               eap_sim_state(data, FAILURE);
-               return;
-       }
+       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",
-                         identity, identity_len);
-
-       if (data->reauth) {
+                         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");
-               eap_sim_state(data, FAILURE);
-               return;
+               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);
-               eap_sim_state(data, FAILURE);
-               return;
+               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, identity, identity_len,
-               EAP_SIM_MAX_CHAL,
+               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 "
@@ -481,8 +532,7 @@ static void eap_sim_process_start(struct eap_sm *sm,
        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;
+               goto failed;
        }
 
        identity_len = sm->identity_len;
@@ -503,6 +553,11 @@ static void eap_sim_process_start(struct eap_sm *sm,
                            data->emsk);
 
        eap_sim_state(data, CHALLENGE);
+       return;
+
+failed:
+       data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+       eap_sim_state(data, NOTIFICATION);
 }
 
 
@@ -511,16 +566,14 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
                                      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);
+               data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+               eap_sim_state(data, NOTIFICATION);
                return;
        }
 
@@ -533,22 +586,13 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
        } 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,
+               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, identity,
-                                     identity_len,
+               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;
@@ -563,8 +607,6 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
 {
        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,
@@ -600,6 +642,16 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
 
        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;
@@ -607,29 +659,9 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
        } 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,
+               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 {
@@ -640,7 +672,8 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
        return;
 
 fail:
-       eap_sim_state(data, FAILURE);
+       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);
@@ -691,8 +724,24 @@ static void eap_sim_process(struct eap_sm *sm, void *priv,
        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;
        }
index c98fa18..447f47c 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-TLS (RFC 2716)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -27,6 +21,7 @@ struct eap_tls_data {
        struct eap_ssl_data ssl;
        enum { START, CONTINUE, SUCCESS, FAILURE } state;
        int established;
+       u8 eap_type;
 };
 
 
@@ -71,10 +66,34 @@ static void * eap_tls_init(struct eap_sm *sm)
                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;
@@ -90,8 +109,7 @@ static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
 {
        struct wpabuf *req;
 
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
-                           id);
+       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");
@@ -113,11 +131,11 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
        struct wpabuf *res;
 
        if (data->ssl.state == FRAG_ACK) {
-               return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
+               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, EAP_TYPE_TLS, 0,
+               res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
                                               id);
                goto check_established;
        }
@@ -135,7 +153,7 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
                return NULL;
        }
 
-       res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
+       res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
 
 check_established:
        if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
@@ -152,10 +170,17 @@ check_established:
 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;
 
-       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &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;
@@ -184,7 +209,7 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
 {
        struct eap_tls_data *data = priv;
        if (eap_server_tls_process(sm, &data->ssl, respData, data,
-                                  EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
+                                  data->eap_type, NULL, eap_tls_process_msg) <
            0)
                eap_tls_state(data, FAILURE);
 }
@@ -284,3 +309,34 @@ int eap_server_tls_register(void)
                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 */
index 0bb9d14..9efb5b2 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TLS/PEAP/TTLS/FAST server common functions
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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)
 {
@@ -137,8 +143,7 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
        if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
                plen += 4;
 
-       req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
-                           EAP_CODE_REQUEST, id);
+       req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
        if (req == NULL)
                return NULL;
 
@@ -174,8 +179,7 @@ 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);
+       req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
        if (req == NULL)
                return NULL;
        wpa_printf(MSG_DEBUG, "SSL: Building ACK");
@@ -224,6 +228,14 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
                        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");
@@ -285,6 +297,13 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
                           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 "
@@ -365,7 +384,13 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
        size_t left;
        int ret, res = 0;
 
-       pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+       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++;
index a2d6f17..67a3dfa 100644 (file)
@@ -2,20 +2,13 @@
  * EAP server method: EAP-TNC (Trusted Network Connect)
  * Copyright (c) 2007-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 "eap_i.h"
 #include "tncs.h"
 
index 398d0f1..647bd2f 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / EAP-TTLS (RFC 5281)
  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -680,6 +674,13 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
                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). */
@@ -985,11 +986,12 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
        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 (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 "
index 0dd0aca..30f600d 100644 (file)
@@ -2,14 +2,8 @@
  * hostapd / Test method for vendor specific (expanded) EAP type
  * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -18,7 +12,7 @@
 #include "eap_i.h"
 
 
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
 #define EAP_VENDOR_TYPE 0xfcfbfaf9
 
 
index 556882d..97ec0c0 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-WSC server for Wi-Fi Protected Setup
  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 248b216..1b9d701 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -23,6 +17,9 @@
 
 #include "includes.h"
 #include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
 
 #include "common.h"
 #include "crypto/random.h"
 
 struct eap_sim_pseudonym {
        struct eap_sim_pseudonym *next;
-       u8 *identity;
-       size_t identity_len;
-       char *pseudonym;
+       char *permanent; /* permanent username */
+       char *pseudonym; /* pseudonym username */
 };
 
 struct eap_sim_db_pending {
        struct eap_sim_db_pending *next;
-       u8 imsi[20];
-       size_t imsi_len;
+       char imsi[20];
        enum { PENDING, SUCCESS, FAILURE } state;
        void *cb_session_ctx;
        struct os_time timestamp;
@@ -72,19 +67,316 @@ struct eap_sim_db_data {
        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 u8 *imsi,
-                      size_t imsi_len, int aka)
+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 && entry->imsi_len == imsi_len &&
-                   os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
+               if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
                        if (prev)
                                prev->next = entry->next;
                        else
@@ -119,7 +411,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
         * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
         */
 
-       entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
+       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");
@@ -197,7 +489,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
         * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
         */
 
-       entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
+       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");
@@ -346,6 +638,7 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
        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)");
@@ -395,11 +688,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
  * @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 *
+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)
@@ -411,10 +706,23 @@ void * eap_sim_db_init(const char *config,
        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))
-                       goto fail;
+               if (eap_sim_db_open_socket(data)) {
+                       wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
+                                  "connection not available - will retry "
+                                  "later");
+               }
        }
 
        return data;
@@ -429,7 +737,7 @@ fail:
 
 static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
 {
-       os_free(p->identity);
+       os_free(p->permanent);
        os_free(p->pseudonym);
        os_free(p);
 }
@@ -437,7 +745,7 @@ static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
 
 static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
 {
-       os_free(r->identity);
+       os_free(r->permanent);
        os_free(r->reauth_id);
        os_free(r);
 }
@@ -454,6 +762,13 @@ void eap_sim_db_deinit(void *priv)
        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);
 
@@ -520,9 +835,8 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
 
 /**
  * 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
+ * @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
@@ -534,9 +848,6 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
  * 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
@@ -545,39 +856,28 @@ static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
  * 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,
+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_data *data = priv;
        struct eap_sim_db_pending *entry;
        int len, ret;
-       size_t i;
        char msg[40];
+       const char *imsi;
+       size_t imsi_len;
 
-       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);
+       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;
        }
-       wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
-                         identity, identity_len);
+       imsi = username + 1;
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
+                  imsi);
 
-       entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
+       entry = eap_sim_db_get_pending(data, imsi, 0);
        if (entry) {
                int num_chal;
                if (entry->state == FAILURE) {
@@ -612,18 +912,19 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
                        return EAP_SIM_DB_FAILURE;
        }
 
+       imsi_len = os_strlen(imsi);
        len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
-       if (len < 0 || len + identity_len >= sizeof(msg))
+       if (len < 0 || len + imsi_len >= sizeof(msg))
                return EAP_SIM_DB_FAILURE;
-       os_memcpy(msg + len, identity, identity_len);
-       len += identity_len;
+       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_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
-                   "data for IMSI", identity, identity_len);
+       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;
 
@@ -632,8 +933,7 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
                return EAP_SIM_DB_FAILURE;
 
        os_get_time(&entry->timestamp);
-       os_memcpy(entry->imsi, identity, identity_len);
-       entry->imsi_len = identity_len;
+       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);
@@ -643,189 +943,6 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
 }
 
 
-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;
@@ -848,8 +965,8 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
 
 /**
  * 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
+ * @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
@@ -857,18 +974,31 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
  * 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)
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
+                                    enum eap_sim_db_method method)
 {
-       struct eap_sim_db_data *data = priv;
-       return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
-                                  EAP_SIM_PSEUDONYM_PREFIX);
+       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
- * @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
+ * @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
@@ -877,19 +1007,31 @@ char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
  * has been completed successfully. Caller is responsible for freeing the
  * returned buffer.
  */
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
+                                    enum eap_sim_db_method method)
 {
-       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);
+       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
- * @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
+ * @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.
@@ -898,20 +1040,22 @@ char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
  * 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)
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+                            const char *permanent, 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);
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
+                  "username '%s'", pseudonym, permanent);
 
        /* 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);
-
+#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);
@@ -927,14 +1071,12 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
        }
 
        p->next = data->pseudonyms;
-       p->identity = os_malloc(identity_len);
-       if (p->identity == NULL) {
+       p->permanent = os_strdup(permanent);
+       if (p->permanent == 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;
 
@@ -944,18 +1086,16 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
 
 
 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)
+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;
 
-       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);
+       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 "
@@ -970,14 +1110,12 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
                }
 
                r->next = data->reauths;
-               r->identity = os_malloc(identity_len);
-               if (r->identity == NULL) {
+               r->permanent = os_strdup(permanent);
+               if (r->permanent == 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");
@@ -992,7 +1130,7 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
 /**
  * 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)
+ * @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
@@ -1005,20 +1143,24 @@ eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
  * 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)
+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_db_data *data = priv;
        struct eap_sim_reauth *r;
 
-       r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
-                                      counter);
+       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);
-       r->aka_prime = 0;
 
        return 0;
 }
@@ -1027,9 +1169,8 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity,
 #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
+ * @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.
@@ -1043,20 +1184,25 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity,
  * 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)
+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_db_data *data = priv;
        struct eap_sim_reauth *r;
 
-       r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
-                                      counter);
+       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;
 
-       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);
@@ -1068,66 +1214,75 @@ int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
 
 /**
  * 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
+ * @data: Private data pointer from eap_sim_db_init()
+ * @pseudonym: Pseudonym username
+ * Returns: Pointer to permanent username or %NULL if not found
  */
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
-                                   size_t identity_len, size_t *len)
+const char *
+eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
 {
-       struct eap_sim_db_data *data = priv;
        struct eap_sim_pseudonym *p;
 
-       if (identity == NULL)
-               return NULL;
+#ifdef CONFIG_SQLITE
+       if (data->sqlite_db)
+               return db_get_pseudonym(data, pseudonym);
+#endif /* CONFIG_SQLITE */
 
-       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;
+       p = data->pseudonyms;
+       while (p) {
+               if (os_strcmp(p->pseudonym, pseudonym) == 0)
+                       return p->permanent;
+               p = p->next;
+       }
 
-       *len = p->identity_len;
-       return p->identity;
+       return NULL;
 }
 
 
 /**
  * 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
+ * @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(void *priv, const u8 *identity,
-                           size_t identity_len)
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+                           const char *reauth_id)
 {
-       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);
+#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
- * @priv: Private data pointer from eap_sim_db_init()
+ * @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(void *priv, struct eap_sim_reauth *reauth)
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+                             struct eap_sim_reauth *reauth)
 {
-       struct eap_sim_db_data *data = priv;
        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) {
@@ -1146,9 +1301,8 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
 
 /**
  * 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
+ * @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
@@ -1161,9 +1315,6 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
  * 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
@@ -1172,40 +1323,29 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
  * 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)
+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_data *data = priv;
        struct eap_sim_db_pending *entry;
        int len;
-       size_t i;
        char msg[40];
+       const char *imsi;
+       size_t imsi_len;
 
-       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);
+       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;
        }
-       wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
-                         identity, identity_len);
+       imsi = username + 1;
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+                  imsi);
 
-       entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
+       entry = eap_sim_db_get_pending(data, imsi, 1);
        if (entry) {
                if (entry->state == FAILURE) {
                        os_free(entry);
@@ -1236,14 +1376,15 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
                        return EAP_SIM_DB_FAILURE;
        }
 
+       imsi_len = os_strlen(imsi);
        len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
-       if (len < 0 || len + identity_len >= sizeof(msg))
+       if (len < 0 || len + imsi_len >= sizeof(msg))
                return EAP_SIM_DB_FAILURE;
-       os_memcpy(msg + len, identity, identity_len);
-       len += identity_len;
+       os_memcpy(msg + len, imsi, imsi_len);
+       len += imsi_len;
 
-       wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
-                   "data for IMSI", identity, identity_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;
 
@@ -1253,8 +1394,7 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
 
        os_get_time(&entry->timestamp);
        entry->aka = 1;
-       os_memcpy(entry->imsi, identity, identity_len);
-       entry->imsi_len = identity_len;
+       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);
@@ -1266,9 +1406,8 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
 
 /**
  * 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
+ * @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
@@ -1279,42 +1418,35 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
  * 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)
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+                            const char *username,
+                            const u8 *auts, const u8 *_rand)
 {
-       struct eap_sim_db_data *data = priv;
-       size_t i;
+       const char *imsi;
+       size_t imsi_len;
 
-       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);
+       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 + identity_len >= sizeof(msg))
+               if (len < 0 || len + imsi_len >= sizeof(msg))
                        return -1;
-               os_memcpy(msg + len, identity, identity_len);
-               len += identity_len;
+               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)
@@ -1328,11 +1460,35 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity,
                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);
+               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)
+{
+       size_t pos;
+
+       if (identity == NULL)
+               return NULL;
+
+       for (pos = 0; pos < identity_len; pos++) {
+               if (identity[pos] == '@' || identity[pos] == '\0')
+                       break;
+       }
+
+       return dup_binstr(identity, pos);
+}
index ab89ae9..53a1a7c 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2008, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_SIM_DB_H
 #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
+};
 
-void * eap_sim_db_init(const char *config,
-                      void (*get_complete_cb)(void *ctx, void *session_ctx),
-                      void *ctx);
+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(void *priv, const u8 *identity,
-                               size_t identity_len, int max_chal,
+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
 
-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_pseudonym(struct eap_sim_db_data *data,
+                                    enum eap_sim_db_method method);
 
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
+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(void *priv, const u8 *identity,
-                            size_t identity_len, char *pseudonym);
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+                            const char *permanent, 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);
+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 u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
-                                   size_t identity_len, size_t *len);
+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;
-       u8 *identity;
-       size_t identity_len;
-       char *reauth_id;
+       char *permanent; /* Permanent username */
+       char *reauth_id; /* Fast re-authentication username */
        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];
@@ -74,18 +76,20 @@ struct eap_sim_reauth {
 };
 
 struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
-                           size_t identity_len);
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+                           const char *reauth_id);
 
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+                             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_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(void *priv, const u8 *identity,
-                            size_t identity_len, const u8 *auts,
+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 */
index c34c401..11f5827 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TLS/PEAP/TTLS/FAST server common functions
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAP_TLS_COMMON_H
@@ -68,7 +62,12 @@ struct eap_ssl_data {
  /* 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);
index f5bbb14..512ba30 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 initiator (RFC 4306) for EAP-IKEV2
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -996,7 +990,7 @@ static int ikev2_build_kei(struct ikev2_initiator_data *data,
         */
        wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
        wpabuf_put_buf(msg, pv);
-       os_free(pv);
+       wpabuf_free(pv);
 
        plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
        WPA_PUT_BE16(phdr->payload_length, plen);
index 8349fbe..051a938 100644 (file)
@@ -2,14 +2,8 @@
  * IKEv2 initiator (RFC 4306) for EAP-IKEV2
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IKEV2_H
index 637b6f8..e429f1e 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -857,12 +851,10 @@ enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
        unsigned char *decoded;
        size_t decoded_len;
 
-       buf = os_malloc(len + 1);
+       buf = dup_binstr(msg, len);
        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) {
index 18a3a1f..ac7251b 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TNCS_H
index a0f0e8d..b6e0b13 100644 (file)
@@ -2,14 +2,8 @@
  * IEEE 802.1X-2004 Authenticator - State dump
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index e600954..c3ccb46 100644 (file)
@@ -2,14 +2,8 @@
  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -763,7 +757,8 @@ SM_STEP(CTRL_DIR)
 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 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;
@@ -844,6 +839,15 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
 
        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;
 }
 
index 724bf8b..b50bbdd 100644 (file)
@@ -2,14 +2,8 @@
  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAPOL_AUTH_SM_H
@@ -83,7 +77,8 @@ 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 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,
index 1000da4..d7f893a 100644 (file)
@@ -2,14 +2,8 @@
  * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions)
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAPOL_AUTH_SM_I_H
@@ -163,6 +157,7 @@ struct eapol_state_machine {
                              * 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;
index ffc6619..9b054fc 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -22,6 +16,7 @@
 #include "crypto/md5.h"
 #include "common/eapol_common.h"
 #include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
 #include "eapol_supp_sm.h"
 
 #define STATE_MACHINE_DATA struct eapol_sm
@@ -142,49 +137,13 @@ struct eapol_sm {
        Boolean cached_pmk;
 
        Boolean unicast_key_received, broadcast_key_received;
+#ifdef CONFIG_EAP_PROXY
+       Boolean use_eap_proxy;
+       struct eap_proxy_sm *eap_proxy;
+#endif /* CONFIG_EAP_PROXY */
 };
 
 
-#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);
@@ -268,6 +227,15 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
 
        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;
 }
 
 
@@ -500,6 +468,17 @@ SM_STATE(SUPP_BE, SUCCESS)
        sm->keyRun = TRUE;
        sm->suppSuccess = TRUE;
 
+#ifdef CONFIG_EAP_PROXY
+       if (sm->use_eap_proxy) {
+               if (eap_proxy_key_available(sm->eap_proxy)) {
+                       /* New key received - clear IEEE 802.1X EAPOL-Key replay
+                        * counter */
+                       sm->replay_counter_valid = FALSE;
+               }
+               return;
+       }
+#endif /* CONFIG_EAP_PROXY */
+
        if (eap_key_available(sm->eap)) {
                /* New key received - clear IEEE 802.1X EAPOL-Key replay
                 * counter */
@@ -535,6 +514,15 @@ 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;
 }
 
 
@@ -652,6 +640,7 @@ struct eap_key_data {
 
 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;
@@ -659,6 +648,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
        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)
@@ -671,9 +661,12 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
                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);
-       if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
+       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;
        }
@@ -739,7 +732,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
        }
        wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
 
-       key_len = be_to_host16(hdr->length) - sizeof(*key);
+       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);
@@ -810,6 +803,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
                                sm->ctx->eapol_done_cb(sm->ctx->ctx);
                }
        }
+#endif /* CONFIG_FIPS */
 }
 
 
@@ -828,6 +822,19 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
        struct wpabuf *resp;
 
        wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+
+#ifdef CONFIG_EAP_PROXY
+       if (sm->use_eap_proxy) {
+               /* Get EAP Response from EAP Proxy */
+               resp = eap_proxy_get_eapRespData(sm->eap_proxy);
+               if (resp == NULL) {
+                       wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
+                                  "response data not available");
+                       return;
+               }
+       } else
+#endif /* CONFIG_EAP_PROXY */
+
        resp = eap_get_eapRespData(sm->eap);
        if (resp == NULL) {
                wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
@@ -905,6 +912,13 @@ void eapol_sm_step(struct eapol_sm *sm)
                SM_STEP_RUN(SUPP_PAE);
                SM_STEP_RUN(KEY_RX);
                SM_STEP_RUN(SUPP_BE);
+#ifdef CONFIG_EAP_PROXY
+               if (sm->use_eap_proxy) {
+                       /* Drive the EAP proxy state machine */
+                       if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
+                               sm->changed = TRUE;
+               } else
+#endif /* CONFIG_EAP_PROXY */
                if (eap_peer_sm_step(sm->eap))
                        sm->changed = TRUE;
                if (!sm->changed)
@@ -1092,6 +1106,13 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
                len += ret;
        }
 
+#ifdef CONFIG_EAP_PROXY
+       if (sm->use_eap_proxy)
+               len += eap_proxy_sm_get_status(sm->eap_proxy,
+                                              buf + len, buflen - len,
+                                              verbose);
+       else
+#endif /* CONFIG_EAP_PROXY */
        len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
 
        return len;
@@ -1249,6 +1270,16 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
                        wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
                                   "frame");
                        sm->eapolEap = TRUE;
+#ifdef CONFIG_EAP_PROXY
+                       if (sm->use_eap_proxy) {
+                               eap_proxy_packet_update(
+                                       sm->eap_proxy,
+                                       wpabuf_mhead_u8(sm->eapReqData),
+                                       wpabuf_len(sm->eapReqData));
+                               wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
+                                          "EAP Req updated");
+                       }
+#endif /* CONFIG_EAP_PROXY */
                        eapol_sm_step(sm);
                }
                break;
@@ -1409,6 +1440,9 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
                return;
 
        sm->config = config;
+#ifdef CONFIG_EAP_PROXY
+       sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
+#endif /* CONFIG_EAP_PROXY */
 
        if (conf == NULL)
                return;
@@ -1417,6 +1451,12 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
        sm->conf.required_keys = conf->required_keys;
        sm->conf.fast_reauth = conf->fast_reauth;
        sm->conf.workaround = conf->workaround;
+#ifdef CONFIG_EAP_PROXY
+       if (sm->use_eap_proxy) {
+               /* Using EAP Proxy, so skip EAP state machine update */
+               return;
+       }
+#endif /* CONFIG_EAP_PROXY */
        if (sm->eap) {
                eap_set_fast_reauth(sm->eap, conf->fast_reauth);
                eap_set_workaround(sm->eap, conf->workaround);
@@ -1441,6 +1481,22 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
        const u8 *eap_key;
        size_t eap_len;
 
+#ifdef CONFIG_EAP_PROXY
+       if (sm->use_eap_proxy) {
+               /* Get key from EAP proxy */
+               if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
+                       wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+                       return -1;
+               }
+               eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
+               if (eap_key == NULL) {
+                       wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
+                                  "eapKeyData");
+                       return -1;
+               }
+               goto key_fetched;
+       }
+#endif /* CONFIG_EAP_PROXY */
        if (sm == NULL || !eap_key_available(sm->eap)) {
                wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
                return -1;
@@ -1450,6 +1506,9 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
                wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
                return -1;
        }
+#ifdef CONFIG_EAP_PROXY
+key_fetched:
+#endif /* CONFIG_EAP_PROXY */
        if (len > eap_len) {
                wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
                           "available (len=%lu)",
@@ -1474,6 +1533,10 @@ void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
 {
        if (sm) {
                sm->userLogoff = logoff;
+               if (!logoff) {
+                       /* If there is a delayed txStart queued, start now. */
+                       sm->startWhen = 0;
+               }
                eapol_sm_step(sm);
        }
 }
@@ -1491,10 +1554,7 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
        if (sm == NULL)
                return;
        wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
-       sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
-       sm->suppPortStatus = Authorized;
-       eapol_sm_set_port_authorized(sm);
-       sm->portValid = TRUE;
+       sm->eapSuccess = TRUE;
        eap_notify_success(sm->eap);
        eapol_sm_step(sm);
 }
@@ -1766,7 +1826,8 @@ static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
        switch (variable) {
        case EAPOL_idleWhile:
                sm->idleWhile = value;
-               eapol_enable_timer_tick(sm);
+               if (sm->idleWhile > 0)
+                       eapol_enable_timer_tick(sm);
                break;
        }
 }
@@ -1835,6 +1896,26 @@ static void eapol_sm_notify_cert(void *ctx, int depth, const char *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,
@@ -1847,7 +1928,9 @@ static struct eapol_callbacks eapol_cb =
        eapol_sm_get_config_blob,
        eapol_sm_notify_pending,
        eapol_sm_eap_param_needed,
-       eapol_sm_notify_cert
+       eapol_sm_notify_cert,
+       eapol_sm_notify_status,
+       eapol_sm_set_anon_id
 };
 
 
@@ -1891,6 +1974,14 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
                return NULL;
        }
 
+#ifdef CONFIG_EAP_PROXY
+       sm->use_eap_proxy = FALSE;
+       sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
+       if (sm->eap_proxy == NULL) {
+               wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
+       }
+#endif /* CONFIG_EAP_PROXY */
+
        /* Initialize EAPOL state machines */
        sm->initialize = TRUE;
        eapol_sm_step(sm);
@@ -1917,8 +2008,27 @@ void eapol_sm_deinit(struct eapol_sm *sm)
        eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
        eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
        eap_peer_sm_deinit(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+       eap_proxy_deinit(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
        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;
+}
index bcb00b5..c4b87da 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EAPOL_SUPP_SM_H
@@ -236,10 +230,28 @@ struct eapol_ctx {
         * 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);
@@ -272,6 +284,9 @@ 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)
 {
@@ -363,6 +378,14 @@ 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 */
index c7b5014..dd825b5 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet interface definition
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index e24277c..2e9a04c 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2005, Sam Leffler <sam@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 93e15eb..1419830 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling with Linux packet sockets
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 6ce29aa..23b8ddc 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index 5e3f6e9..b01e830 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling example with dummy functions
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
  */
index 8156e29..45aef56 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 79d2968..6b117ca 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling with privilege separation
  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -179,7 +173,7 @@ struct l2_packet_data * l2_packet_init(
        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)");
+               perror("l2-pkt-privsep: bind(PF_UNIX)");
                goto fail;
        }
 
index f76b386..b6e5088 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Layer2 packet handling with WinPcap RX thread
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index c0009ce..242297e 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P module
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -55,13 +49,40 @@ static void p2p_expire_peers(struct p2p_data *p2p)
 {
        struct p2p_device *dev, *n;
        struct os_time now;
+       size_t i;
 
        os_get_time(&now);
        dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
                if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec)
                        continue;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
-                       "entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
+
+               if (p2p->cfg->go_connected &&
+                   p2p->cfg->go_connected(p2p->cfg->cb_ctx,
+                                          dev->info.p2p_device_addr)) {
+                       /*
+                        * We are connected as a client to a group in which the
+                        * peer is the GO, so do not expire the peer entry.
+                        */
+                       os_get_time(&dev->last_seen);
+                       continue;
+               }
+
+               for (i = 0; i < p2p->num_groups; i++) {
+                       if (p2p_group_is_client_connected(
+                                   p2p->groups[i], dev->info.p2p_device_addr))
+                               break;
+               }
+               if (i < p2p->num_groups) {
+                       /*
+                        * The peer is connected as a client in a group where
+                        * we are the GO, so do not expire the peer entry.
+                        */
+                       os_get_time(&dev->last_seen);
+                       continue;
+               }
+
+               p2p_dbg(p2p, "Expiring old peer entry " MACSTR,
+                       MAC2STR(dev->info.p2p_device_addr));
                dl_list_del(&dev->list);
                p2p_device_free(p2p, dev);
        }
@@ -108,6 +129,8 @@ static const char * p2p_state_txt(int state)
                return "INVITE_LISTEN";
        case P2P_SEARCH_WHEN_READY:
                return "SEARCH_WHEN_READY";
+       case P2P_CONTINUE_SEARCH_WHEN_READY:
+               return "CONTINUE_SEARCH_WHEN_READY";
        default:
                return "?";
        }
@@ -129,14 +152,14 @@ u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
 }
 
 
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
 {
        struct p2p_device *dev = NULL;
 
-       if (!iface_addr || !p2p)
+       if (!addr || !p2p)
                return;
 
-       dev = p2p_get_device_interface(p2p, iface_addr);
+       dev = p2p_get_device(p2p, addr);
        if (dev)
                dev->wps_prov_info = 0;
 }
@@ -144,7 +167,7 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
 
 void p2p_set_state(struct p2p_data *p2p, int new_state)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
+       p2p_dbg(p2p, "State %s -> %s",
                p2p_state_txt(p2p->state), p2p_state_txt(new_state));
        p2p->state = new_state;
 }
@@ -152,8 +175,7 @@ void p2p_set_state(struct p2p_data *p2p, int new_state)
 
 void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Set timeout (state=%s): %u.%06u sec",
+       p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",
                p2p_state_txt(p2p->state), sec, usec);
        eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
        eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
@@ -162,8 +184,7 @@ void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
 
 void p2p_clear_timeout(struct p2p_data *p2p)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear timeout (state=%s)",
-               p2p_state_txt(p2p->state));
+       p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state));
        eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
 }
 
@@ -174,8 +195,10 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
        struct p2p_go_neg_results res;
        p2p_clear_timeout(p2p);
        p2p_set_state(p2p, P2P_IDLE);
-       if (p2p->go_neg_peer)
+       if (p2p->go_neg_peer) {
+               p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
                p2p->go_neg_peer->wps_method = WPS_NOT_READY;
+       }
        p2p->go_neg_peer = NULL;
 
        os_memset(&res, 0, sizeof(res));
@@ -190,27 +213,36 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
 }
 
 
-static void p2p_listen_in_find(struct p2p_data *p2p)
+static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
 {
        unsigned int r, tu;
        int freq;
        struct wpabuf *ies;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Starting short listen state (state=%s)",
+       p2p_dbg(p2p, "Starting short listen state (state=%s)",
                p2p_state_txt(p2p->state));
 
-       freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-                                  p2p->cfg->channel);
+       freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
        if (freq < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown regulatory class/channel");
+               p2p_dbg(p2p, "Unknown regulatory class/channel");
                return;
        }
 
        os_get_random((u8 *) &r, sizeof(r));
        tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
              p2p->min_disc_int) * 100;
+       if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
+               tu = p2p->max_disc_tu;
+       if (!dev_disc && tu < 100)
+               tu = 100; /* Need to wait in non-device discovery use cases */
+       if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen)
+               tu = p2p->cfg->max_listen * 1000 / 1024;
+
+       if (tu == 0) {
+               p2p_dbg(p2p, "Skip listen state since duration was 0 TU");
+               p2p_set_timeout(p2p, 0, 0);
+               return;
+       }
 
        p2p->pending_listen_freq = freq;
        p2p->pending_listen_sec = 0;
@@ -222,8 +254,7 @@ static void p2p_listen_in_find(struct p2p_data *p2p)
 
        if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,
                    ies) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to start listen mode");
+               p2p_dbg(p2p, "Failed to start listen mode");
                p2p->pending_listen_freq = 0;
        }
        wpabuf_free(ies);
@@ -235,14 +266,11 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
        int freq;
        struct wpabuf *ies;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Going to listen(only) state");
+       p2p_dbg(p2p, "Going to listen(only) state");
 
-       freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-                                  p2p->cfg->channel);
+       freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
        if (freq < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown regulatory class/channel");
+               p2p_dbg(p2p, "Unknown regulatory class/channel");
                return -1;
        }
 
@@ -251,8 +279,11 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
        p2p->pending_listen_usec = (timeout % 1000) * 1000;
 
        if (p2p->p2p_scan_running) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: p2p_scan running - delay start of listen state");
+               if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
+                       p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen");
+                       return 0;
+               }
+               p2p_dbg(p2p, "p2p_scan running - delay start of listen state");
                p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
                return 0;
        }
@@ -262,8 +293,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
                return -1;
 
        if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to start listen mode");
+               p2p_dbg(p2p, "Failed to start listen mode");
                p2p->pending_listen_freq = 0;
                wpabuf_free(ies);
                return -1;
@@ -345,9 +375,7 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
                        oldest = dev;
        }
        if (count + 1 > p2p->cfg->max_peers && oldest) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Remove oldest peer entry to make room for a new "
-                       "peer");
+               p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
                dl_list_del(&oldest->list);
                p2p_device_free(p2p, oldest);
        }
@@ -409,13 +437,25 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
                        continue; /* ignore our own entry */
                dev = p2p_get_device(p2p, cli->p2p_device_addr);
                if (dev) {
-                       /*
-                        * Update information only if we have not received this
-                        * directly from the client.
-                        */
                        if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY |
-                                         P2P_DEV_PROBE_REQ_ONLY))
+                                         P2P_DEV_PROBE_REQ_ONLY)) {
+                               /*
+                                * Update information since we have not
+                                * received this directly from the client.
+                                */
                                p2p_copy_client_info(dev, cli);
+                       } else {
+                               /*
+                                * Need to update P2P Client Discoverability
+                                * flag since it is valid only in P2P Group
+                                * Info attribute.
+                                */
+                               dev->info.dev_capab &=
+                                       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+                               dev->info.dev_capab |=
+                                       cli->dev_capab &
+                                       P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+                       }
                        if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
                                dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
                        }
@@ -444,8 +484,8 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
 }
 
 
-static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
-                             const struct p2p_message *msg)
+static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
+                             int probe_req, const struct p2p_message *msg)
 {
        os_memcpy(dev->info.device_name, msg->device_name,
                  sizeof(dev->info.device_name));
@@ -498,7 +538,13 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
        }
 
        if (msg->capability) {
-               dev->info.dev_capab = msg->capability[0];
+               /*
+                * P2P Client Discoverability bit is reserved in all frames
+                * that use this function, so do not change its value here.
+                */
+               dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+               dev->info.dev_capab |= msg->capability[0] &
+                       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
                dev->info.group_capab = msg->capability[1];
        }
 
@@ -509,21 +555,33 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
        }
 
        if (!probe_req) {
-               dev->info.config_methods = msg->config_methods ?
+               u16 new_config_methods;
+               new_config_methods = msg->config_methods ?
                        msg->config_methods : msg->wps_config_methods;
+               if (new_config_methods &&
+                   dev->info.config_methods != new_config_methods) {
+                       p2p_dbg(p2p, "Update peer " MACSTR
+                               " config_methods 0x%x -> 0x%x",
+                               MAC2STR(dev->info.p2p_device_addr),
+                               dev->info.config_methods,
+                               new_config_methods);
+                       dev->info.config_methods = new_config_methods;
+               }
        }
 }
 
 
 /**
- * p2p_add_device - Add peer entries based on scan results
+ * p2p_add_device - Add peer entries based on scan results or P2P frames
  * @p2p: P2P module context from p2p_init()
  * @addr: Source address of Beacon or Probe Response frame (may be either
  *     P2P Device Address or P2P Interface Address)
  * @level: Signal level (signal strength of the received frame from the peer)
  * @freq: Frequency on which the Beacon or Probe Response frame was received
+ * @rx_time: Time when the result was received
  * @ies: IEs from the Beacon or Probe Response frame
  * @ies_len: Length of ies buffer in octets
+ * @scan_res: Whether this was based on scan results
  * Returns: 0 on success, -1 on failure
  *
  * If the scan result is for a GO, the clients in the group will also be added
@@ -531,18 +589,19 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
  * like Provision Discovery Request that contains P2P Capability and P2P Device
  * Info attributes.
  */
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-                  const u8 *ies, size_t ies_len)
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+                  struct os_time *rx_time, int level, const u8 *ies,
+                  size_t ies_len, int scan_res)
 {
        struct p2p_device *dev;
        struct p2p_message msg;
        const u8 *p2p_dev_addr;
        int i;
+       struct os_time time_now;
 
        os_memset(&msg, 0, sizeof(msg));
        if (p2p_parse_ies(ies, ies_len, &msg)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to parse P2P IE for a device entry");
+               p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
                p2p_parse_free(&msg);
                return -1;
        }
@@ -552,18 +611,16 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
        else if (msg.device_id)
                p2p_dev_addr = msg.device_id;
        else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore scan data without P2P Device Info or "
-                       "P2P Device Id");
+               p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
                p2p_parse_free(&msg);
                return -1;
        }
 
        if (!is_zero_ether_addr(p2p->peer_filter) &&
            os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
-                       "filter for " MACSTR " due to peer filter",
-                       MAC2STR(p2p_dev_addr));
+               p2p_dbg(p2p, "Do not add peer filter for " MACSTR
+                       " due to peer filter", MAC2STR(p2p_dev_addr));
+               p2p_parse_free(&msg);
                return 0;
        }
 
@@ -572,7 +629,29 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
                p2p_parse_free(&msg);
                return -1;
        }
-       os_get_time(&dev->last_seen);
+
+       if (rx_time == NULL) {
+               os_get_time(&time_now);
+               rx_time = &time_now;
+       }
+
+       /*
+        * Update the device entry only if the new peer
+        * entry is newer than the one previously stored.
+        */
+       if (dev->last_seen.sec > 0 &&
+           os_time_before(rx_time, &dev->last_seen)) {
+               p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
+                       (unsigned int) rx_time->sec,
+                       (unsigned int) rx_time->usec,
+                       (unsigned int) dev->last_seen.sec,
+                       (unsigned int) dev->last_seen.usec);
+               p2p_parse_free(&msg);
+               return -1;
+       }
+
+       os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time));
+
        dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
 
        if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
@@ -593,27 +672,26 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
                else
                        ds_freq = 2407 + *msg.ds_params * 5;
                if (freq != ds_freq) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Update Listen frequency based on DS "
-                               "Parameter Set IE: %d -> %d MHz",
+                       p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz",
                                freq, ds_freq);
                        freq = ds_freq;
                }
        }
 
-       if (dev->listen_freq && dev->listen_freq != freq) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Update Listen frequency based on scan "
-                       "results (" MACSTR " %d -> %d MHz (DS param %d)",
+       if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
+               p2p_dbg(p2p, "Update Listen frequency based on scan results ("
+                       MACSTR " %d -> %d MHz (DS param %d)",
                        MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
                        freq, msg.ds_params ? *msg.ds_params : -1);
        }
-       dev->listen_freq = freq;
-       if (msg.group_info)
-               dev->oper_freq = freq;
+       if (scan_res) {
+               dev->listen_freq = freq;
+               if (msg.group_info)
+                       dev->oper_freq = freq;
+       }
        dev->info.level = level;
 
-       p2p_copy_wps_info(dev, 0, &msg);
+       p2p_copy_wps_info(p2p, dev, 0, &msg);
 
        for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
                wpabuf_free(dev->info.wps_vendor_ext[i]);
@@ -629,8 +707,15 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
                        break;
        }
 
-       p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info,
-                             msg.group_info_len);
+       if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+       }
+
+       if (scan_res) {
+               p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
+                                     msg.group_info, msg.group_info_len);
+       }
 
        p2p_parse_free(&msg);
 
@@ -640,11 +725,32 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
        if (dev->flags & P2P_DEV_REPORTED)
                return 0;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Peer found with Listen frequency %d MHz", freq);
+       p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
+               freq, (unsigned int) rx_time->sec,
+               (unsigned int) rx_time->usec);
        if (dev->flags & P2P_DEV_USER_REJECTED) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Do not report rejected device");
+               p2p_dbg(p2p, "Do not report rejected device");
+               return 0;
+       }
+
+       if (dev->info.config_methods == 0 &&
+           (freq == 2412 || freq == 2437 || freq == 2462)) {
+               /*
+                * If we have only seen a Beacon frame from a GO, we do not yet
+                * know what WPS config methods it supports. Since some
+                * applications use config_methods value from P2P-DEVICE-FOUND
+                * events, postpone reporting this peer until we've fully
+                * discovered its capabilities.
+                *
+                * At least for now, do this only if the peer was detected on
+                * one of the social channels since that peer can be easily be
+                * found again and there are no limitations of having to use
+                * passive scan on this channels, so this can be done through
+                * Probe Response frame that includes the config_methods
+                * information.
+                */
+               p2p_dbg(p2p, "Do not report peer " MACSTR
+                       " with unknown config methods", MAC2STR(addr));
                return 0;
        }
 
@@ -684,6 +790,8 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
                dev->info.wps_vendor_ext[i] = NULL;
        }
 
+       wpabuf_free(dev->info.wfd_subelems);
+
        os_free(dev);
 }
 
@@ -730,9 +838,8 @@ static int p2p_get_next_prog_freq(struct p2p_data *p2p)
                channel = c->reg_class[cl].channel[ch];
        }
 
-       freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
-               "channel: reg_class %u channel %u -> %d MHz",
+       freq = p2p_channel_to_freq(reg_class, channel);
+       p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz",
                reg_class, channel, freq);
        p2p->last_prog_scan_class = reg_class;
        p2p->last_prog_scan_chan = channel;
@@ -747,55 +854,35 @@ static void p2p_search(struct p2p_data *p2p)
 {
        int freq = 0;
        enum p2p_scan_type type;
+       u16 pw_id = DEV_PW_DEFAULT;
+       int res;
 
        if (p2p->drv_in_listen) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
-                       "in Listen state - wait for it to end before "
-                       "continuing");
+               p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing");
                return;
        }
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
 
-       if (p2p->go_neg_peer) {
-               /*
-                * Only scan the known listen frequency of the peer
-                * during GO Negotiation start.
-                */
-               freq = p2p->go_neg_peer->listen_freq;
-               if (freq <= 0)
-                       freq = p2p->go_neg_peer->oper_freq;
-               type = P2P_SCAN_SPECIFIC;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-                       "for freq %u (GO Neg)", freq);
-       } else if (p2p->invite_peer) {
-               /*
-                * Only scan the known listen frequency of the peer
-                * during Invite start.
-                */
-               freq = p2p->invite_peer->listen_freq;
-               if (freq <= 0)
-                       freq = p2p->invite_peer->oper_freq;
-               type = P2P_SCAN_SPECIFIC;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-                       "for freq %u (Invite)", freq);
-       } else if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
-                  (freq = p2p_get_next_prog_freq(p2p)) > 0) {
+       if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
+           (freq = p2p_get_next_prog_freq(p2p)) > 0) {
                type = P2P_SCAN_SOCIAL_PLUS_ONE;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-                       "(+ freq %u)", freq);
+               p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
        } else {
                type = P2P_SCAN_SOCIAL;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
+               p2p_dbg(p2p, "Starting search");
        }
 
-       if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
-                              p2p->num_req_dev_types, p2p->req_dev_types) < 0)
-       {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Scan request failed");
+       res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
+                                p2p->num_req_dev_types, p2p->req_dev_types,
+                                p2p->find_dev_id, pw_id);
+       if (res < 0) {
+               p2p_dbg(p2p, "Scan request failed");
                p2p_continue_find(p2p);
+       } else if (res == 1) {
+               p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes");
+               p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
+               p2p_dbg(p2p, "Running p2p_scan");
                p2p->p2p_scan_running = 1;
                eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
                eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
@@ -807,7 +894,7 @@ static void p2p_search(struct p2p_data *p2p)
 static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct p2p_data *p2p = eloop_ctx;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Find timeout -> stop");
+       p2p_dbg(p2p, "Find timeout -> stop");
        p2p_stop_find(p2p);
 }
 
@@ -818,10 +905,8 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
        enum p2p_after_scan op;
 
        if (p2p->after_scan_tx) {
-               /* TODO: schedule p2p_run_after_scan to be called from TX
-                * status callback(?) */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
-                       "Action frame at p2p_scan completion");
+               p2p->after_scan_tx_in_progress = 1;
+               p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion");
                p2p->cfg->send_action(p2p->cfg->cb_ctx,
                                      p2p->after_scan_tx->freq,
                                      p2p->after_scan_tx->dst,
@@ -841,19 +926,16 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
        case P2P_AFTER_SCAN_NOTHING:
                break;
        case P2P_AFTER_SCAN_LISTEN:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
-                       "requested Listen state");
+               p2p_dbg(p2p, "Start previously requested Listen state");
                p2p_listen(p2p, p2p->pending_listen_sec * 1000 +
                           p2p->pending_listen_usec / 1000);
                return 1;
        case P2P_AFTER_SCAN_CONNECT:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
-                       "requested connect with " MACSTR,
+               p2p_dbg(p2p, "Start previously requested connect with " MACSTR,
                        MAC2STR(p2p->after_scan_peer));
                dev = p2p_get_device(p2p, p2p->after_scan_peer);
                if (dev == NULL) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer not "
-                               "known anymore");
+                       p2p_dbg(p2p, "Peer not known anymore");
                        break;
                }
                p2p_connect_send(p2p, dev);
@@ -868,8 +950,7 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct p2p_data *p2p = eloop_ctx;
        int running;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan timeout "
-               "(running=%d)", p2p->p2p_scan_running);
+       p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running);
        running = p2p->p2p_scan_running;
        /* Make sure we recover from missed scan results callback */
        p2p->p2p_scan_running = 0;
@@ -889,15 +970,15 @@ static void p2p_free_req_dev_types(struct p2p_data *p2p)
 
 int p2p_find(struct p2p_data *p2p, unsigned int timeout,
             enum p2p_discovery_type type,
-            unsigned int num_req_dev_types, const u8 *req_dev_types)
+            unsigned int num_req_dev_types, const u8 *req_dev_types,
+            const u8 *dev_id, unsigned int search_delay)
 {
        int res;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
-               type);
+       p2p_dbg(p2p, "Starting find (type=%d)", type);
+       os_get_time(&p2p->find_start);
        if (p2p->p2p_scan_running) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
-                       "already running");
+               p2p_dbg(p2p, "p2p_scan is already running");
        }
 
        p2p_free_req_dev_types(p2p);
@@ -911,12 +992,20 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
                p2p->num_req_dev_types = num_req_dev_types;
        }
 
+       if (dev_id) {
+               os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN);
+               p2p->find_dev_id = p2p->find_dev_id_buf;
+       } else
+               p2p->find_dev_id = NULL;
+
        p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
        p2p_clear_timeout(p2p);
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
        p2p->find_type = type;
        p2p_device_clear_reported(p2p);
        p2p_set_state(p2p, P2P_SEARCH);
+       p2p->search_delay = search_delay;
+       p2p->in_search_delay = 0;
        eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
        p2p->last_p2p_find_timeout = timeout;
        if (timeout)
@@ -927,33 +1016,32 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
        case P2P_FIND_PROGRESSIVE:
                res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
                                         p2p->num_req_dev_types,
-                                        p2p->req_dev_types);
+                                        p2p->req_dev_types, dev_id,
+                                        DEV_PW_DEFAULT);
                break;
        case P2P_FIND_ONLY_SOCIAL:
                res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
                                         p2p->num_req_dev_types,
-                                        p2p->req_dev_types);
+                                        p2p->req_dev_types, dev_id,
+                                        DEV_PW_DEFAULT);
                break;
        default:
                return -1;
        }
 
        if (res == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
+               p2p_dbg(p2p, "Running p2p_scan");
                p2p->p2p_scan_running = 1;
                eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
                eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
                                       p2p, NULL);
        } else if (res == 1) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
-                       "p2p_scan at this point - will try again after "
-                       "previous scan completes");
+               p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes");
                res = 0;
                p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
                eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
-                       "p2p_scan");
+               p2p_dbg(p2p, "Failed to start p2p_scan");
                p2p_set_state(p2p, P2P_IDLE);
                eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
        }
@@ -964,41 +1052,62 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 
 int p2p_other_scan_completed(struct p2p_data *p2p)
 {
+       if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
+               p2p_set_state(p2p, P2P_SEARCH);
+               p2p_search(p2p);
+               return 1;
+       }
        if (p2p->state != P2P_SEARCH_WHEN_READY)
                return 0;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
-               "now that previous scan was completed");
+       p2p_dbg(p2p, "Starting pending P2P find now that previous scan was completed");
        if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
-                    p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+                    p2p->num_req_dev_types, p2p->req_dev_types,
+                    p2p->find_dev_id, p2p->search_delay) < 0) {
+               p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
                return 0;
+       }
        return 1;
 }
 
 
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
+       p2p_dbg(p2p, "Stopping find");
        eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
        p2p_clear_timeout(p2p);
+       if (p2p->state == P2P_SEARCH ||
+           p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
+           p2p->state == P2P_SEARCH_WHEN_READY)
+               p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
        p2p_set_state(p2p, P2P_IDLE);
        p2p_free_req_dev_types(p2p);
        p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+       if (p2p->go_neg_peer)
+               p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
        p2p->go_neg_peer = NULL;
        p2p->sd_peer = NULL;
        p2p->invite_peer = NULL;
+       p2p_stop_listen_for_freq(p2p, freq);
+}
+
+
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
+{
        if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
-                       "since we are on correct channel for response");
+               p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
                return;
        }
+       if (p2p->in_listen) {
+               p2p->in_listen = 0;
+               p2p_clear_timeout(p2p);
+       }
        if (p2p->drv_in_listen) {
                /*
                 * The driver may not deliver callback to p2p_listen_end()
                 * when the operation gets canceled, so clear the internal
                 * variable that is tracking driver state.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
-                       "drv_in_listen (%d)", p2p->drv_in_listen);
+               p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen);
                p2p->drv_in_listen = 0;
        }
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -1011,81 +1120,107 @@ void p2p_stop_find(struct p2p_data *p2p)
 }
 
 
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
+static int p2p_prepare_channel_pref(struct p2p_data *p2p,
+                                   unsigned int force_freq,
+                                   unsigned int pref_freq)
 {
+       u8 op_class, op_channel;
+       unsigned int freq = force_freq ? force_freq : pref_freq;
+
+       if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
+               p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
+               return -1;
+       }
+
+       if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+               p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
+                       freq, op_class, op_channel);
+               return -1;
+       }
+
+       p2p->op_reg_class = op_class;
+       p2p->op_channel = op_channel;
+
        if (force_freq) {
-               u8 op_reg_class, op_channel;
-               if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
-                                       &op_reg_class, &op_channel) < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unsupported frequency %u MHz",
-                               force_freq);
-                       return -1;
-               }
-               if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
-                                          op_channel)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Frequency %u MHz (oper_class %u "
-                               "channel %u) not allowed for P2P",
-                               force_freq, op_reg_class, op_channel);
-                       return -1;
-               }
-               p2p->op_reg_class = op_reg_class;
-               p2p->op_channel = op_channel;
                p2p->channels.reg_classes = 1;
                p2p->channels.reg_class[0].channels = 1;
                p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
                p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
        } else {
-               u8 op_reg_class, op_channel;
-
-               if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
-                   p2p_supported_freq(p2p, p2p->best_freq_overall) &&
-                   p2p_freq_to_channel(p2p->cfg->country,
-                                       p2p->best_freq_overall,
-                                       &op_reg_class, &op_channel) == 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Select best overall channel as "
-                               "operating channel preference");
-                       p2p->op_reg_class = op_reg_class;
-                       p2p->op_channel = op_channel;
-               } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
-                          p2p_supported_freq(p2p, p2p->best_freq_5) &&
-                          p2p_freq_to_channel(p2p->cfg->country,
-                                              p2p->best_freq_5,
-                                              &op_reg_class, &op_channel) ==
-                          0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Select best 5 GHz channel as "
-                               "operating channel preference");
-                       p2p->op_reg_class = op_reg_class;
-                       p2p->op_channel = op_channel;
-               } else if (!p2p->cfg->cfg_op_channel &&
-                          p2p->best_freq_24 > 0 &&
-                          p2p_supported_freq(p2p, p2p->best_freq_24) &&
-                          p2p_freq_to_channel(p2p->cfg->country,
-                                              p2p->best_freq_24,
-                                              &op_reg_class, &op_channel) ==
-                          0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Select best 2.4 GHz channel as "
-                               "operating channel preference");
-                       p2p->op_reg_class = op_reg_class;
-                       p2p->op_channel = op_channel;
-               } else {
-                       p2p->op_reg_class = p2p->cfg->op_reg_class;
-                       p2p->op_channel = p2p->cfg->op_channel;
-               }
-
                os_memcpy(&p2p->channels, &p2p->cfg->channels,
                          sizeof(struct p2p_channels));
        }
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Own preference for operation channel: "
-               "Operating Class %u Channel %u%s",
+
+       return 0;
+}
+
+
+static void p2p_prepare_channel_best(struct p2p_data *p2p)
+{
+       u8 op_class, op_channel;
+
+       if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
+           p2p_supported_freq(p2p, p2p->best_freq_overall) &&
+           p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+           == 0) {
+               p2p_dbg(p2p, "Select best overall channel as operating channel preference");
+               p2p->op_reg_class = op_class;
+               p2p->op_channel = op_channel;
+       } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
+                  p2p_supported_freq(p2p, p2p->best_freq_5) &&
+                  p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+                  == 0) {
+               p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference");
+               p2p->op_reg_class = op_class;
+               p2p->op_channel = op_channel;
+       } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
+                  p2p_supported_freq(p2p, p2p->best_freq_24) &&
+                  p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+                                      &op_channel) == 0) {
+               p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
+               p2p->op_reg_class = op_class;
+               p2p->op_channel = op_channel;
+       } else {
+               p2p->op_reg_class = p2p->cfg->op_reg_class;
+               p2p->op_channel = p2p->cfg->op_channel;
+       }
+
+       os_memcpy(&p2p->channels, &p2p->cfg->channels,
+                 sizeof(struct p2p_channels));
+}
+
+
+/**
+ * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * @p2p: P2P module context from p2p_init()
+ * @dev: Selected peer device
+ * @force_freq: Forced frequency in MHz or 0 if not forced
+ * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * Returns: 0 on success, -1 on failure (channel not supported for P2P)
+ *
+ * This function is used to do initial operating channel selection for GO
+ * Negotiation prior to having received peer information. The selected channel
+ * may be further optimized in p2p_reselect_channel() once the peer information
+ * is available.
+ */
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+                       unsigned int force_freq, unsigned int pref_freq)
+{
+       if (force_freq || pref_freq) {
+               if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+                       return -1;
+       } else {
+               p2p_prepare_channel_best(p2p);
+       }
+       p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
                p2p->op_reg_class, p2p->op_channel,
                force_freq ? " (forced)" : "");
 
+       if (force_freq)
+               dev->flags |= P2P_DEV_FORCE_FREQ;
+       else
+               dev->flags &= ~P2P_DEV_FORCE_FREQ;
+
        return 0;
 }
 
@@ -1113,41 +1248,38 @@ static void p2p_set_dev_persistent(struct p2p_device *dev,
 int p2p_connect(struct p2p_data *p2p, 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)
+               unsigned int force_freq, int persistent_group,
+               const u8 *force_ssid, size_t force_ssid_len,
+               int pd_before_go_neg, unsigned int pref_freq)
 {
        struct p2p_device *dev;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Request to start group negotiation - peer=" MACSTR
+       p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
                "  GO Intent=%d  Intended Interface Address=" MACSTR
-               " wps_method=%d persistent_group=%d",
+               " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
                MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
-               wps_method, persistent_group);
-
-       if (p2p_prepare_channel(p2p, force_freq) < 0)
-               return -1;
+               wps_method, persistent_group, pd_before_go_neg);
 
-       p2p->ssid_set = 0;
        dev = p2p_get_device(p2p, peer_addr);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Cannot connect to unknown P2P Device " MACSTR,
+               p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
                        MAC2STR(peer_addr));
                return -1;
        }
 
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+               return -1;
+
        if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
                if (!(dev->info.dev_capab &
                      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Cannot connect to P2P Device " MACSTR
+                       p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
                                " that is in a group and is not discoverable",
                                MAC2STR(peer_addr));
                        return -1;
                }
                if (dev->oper_freq <= 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Cannot connect to P2P Device " MACSTR
+                       p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
                                " with incomplete information",
                                MAC2STR(peer_addr));
                        return -1;
@@ -1160,10 +1292,33 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                 */
        }
 
+       p2p->ssid_set = 0;
+       if (force_ssid) {
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+                                 force_ssid, force_ssid_len);
+               os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+               p2p->ssid_len = force_ssid_len;
+               p2p->ssid_set = 1;
+       }
+
        dev->flags &= ~P2P_DEV_NOT_YET_READY;
        dev->flags &= ~P2P_DEV_USER_REJECTED;
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+       if (pd_before_go_neg)
+               dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
+       else {
+               dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+               /*
+                * Assign dialog token and tie breaker here to use the same
+                * values in each retry within the same GO Negotiation exchange.
+                */
+               dev->dialog_token++;
+               if (dev->dialog_token == 0)
+                       dev->dialog_token = 1;
+               dev->tie_breaker = p2p->next_tie_breaker;
+               p2p->next_tie_breaker = !p2p->next_tie_breaker;
+       }
        dev->connect_reqs = 0;
        dev->go_neg_req_sent = 0;
        dev->go_state = UNKNOWN_GO;
@@ -1180,9 +1335,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                 * new GO Negotiation, e.g., when the pending frame was from a
                 * previous attempt at starting a GO Negotiation.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
-                       "previous pending Action frame TX that was waiting "
-                       "for p2p_scan completion");
+               p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
                os_free(p2p->after_scan_tx);
                p2p->after_scan_tx = NULL;
        }
@@ -1190,14 +1343,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
        dev->wps_method = wps_method;
        dev->status = P2P_SC_SUCCESS;
 
-       if (force_freq)
-               dev->flags |= P2P_DEV_FORCE_FREQ;
-       else
-               dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
        if (p2p->p2p_scan_running) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: p2p_scan running - delay connect send");
+               p2p_dbg(p2p, "p2p_scan running - delay connect send");
                p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
                os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
                return 0;
@@ -1211,28 +1358,37 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 int p2p_authorize(struct p2p_data *p2p, 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)
+                 unsigned int force_freq, int persistent_group,
+                 const u8 *force_ssid, size_t force_ssid_len,
+                 unsigned int pref_freq)
 {
        struct p2p_device *dev;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Request to authorize group negotiation - peer=" MACSTR
+       p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
                "  GO Intent=%d  Intended Interface Address=" MACSTR
                " wps_method=%d  persistent_group=%d",
                MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
                wps_method, persistent_group);
 
-       if (p2p_prepare_channel(p2p, force_freq) < 0)
-               return -1;
-
        dev = p2p_get_device(p2p, peer_addr);
        if (dev == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Cannot authorize unknown P2P Device " MACSTR,
+               p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR,
                        MAC2STR(peer_addr));
                return -1;
        }
 
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+               return -1;
+
+       p2p->ssid_set = 0;
+       if (force_ssid) {
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+                                 force_ssid, force_ssid_len);
+               os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+               p2p->ssid_len = force_ssid_len;
+               p2p->ssid_set = 1;
+       }
+
        dev->flags &= ~P2P_DEV_NOT_YET_READY;
        dev->flags &= ~P2P_DEV_USER_REJECTED;
        dev->go_neg_req_sent = 0;
@@ -1244,11 +1400,6 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
        dev->wps_method = wps_method;
        dev->status = P2P_SC_SUCCESS;
 
-       if (force_freq)
-               dev->flags |= P2P_DEV_FORCE_FREQ;
-       else
-               dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
        return 0;
 }
 
@@ -1258,16 +1409,14 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
 {
        os_get_time(&dev->last_seen);
 
-       p2p_copy_wps_info(dev, 0, msg);
+       p2p_copy_wps_info(p2p, dev, 0, msg);
 
        if (msg->listen_channel) {
                int freq;
-               freq = p2p_channel_to_freq((char *) msg->listen_channel,
-                                          msg->listen_channel[3],
+               freq = p2p_channel_to_freq(msg->listen_channel[3],
                                           msg->listen_channel[4]);
                if (freq < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unknown peer Listen channel: "
+                       p2p_dbg(p2p, "Unknown peer Listen channel: "
                                "country=%c%c(0x%02x) reg_class=%u channel=%u",
                                msg->listen_channel[0],
                                msg->listen_channel[1],
@@ -1275,22 +1424,24 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
                                msg->listen_channel[3],
                                msg->listen_channel[4]);
                } else {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update "
-                               "peer " MACSTR " Listen channel: %u -> %u MHz",
+                       p2p_dbg(p2p, "Update peer " MACSTR
+                               " Listen channel: %u -> %u MHz",
                                MAC2STR(dev->info.p2p_device_addr),
                                dev->listen_freq, freq);
                        dev->listen_freq = freq;
                }
        }
 
+       if (msg->wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
+       }
+
        if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
                dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Completed device entry based on data from "
-                       "GO Negotiation Request");
+               p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request");
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Created device entry based on GO Neg Req: "
+               p2p_dbg(p2p, "Created device entry based on GO Neg Req: "
                        MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' "
                        "listen_freq=%d",
                        MAC2STR(dev->info.p2p_device_addr),
@@ -1301,8 +1452,7 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
        dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY;
 
        if (dev->flags & P2P_DEV_USER_REJECTED) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Do not report rejected device");
+               p2p_dbg(p2p, "Do not report rejected device");
                return;
        }
 
@@ -1338,10 +1488,8 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
        int freqs;
        size_t i, j;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation with " MACSTR " completed (%s will be "
-               "GO)", MAC2STR(peer->info.p2p_device_addr),
-               go ? "local end" : "peer");
+       p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
+               MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
 
        os_memset(&res, 0, sizeof(res));
        res.role_go = go;
@@ -1357,8 +1505,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 
        if (go) {
                /* Setup AP mode for WPS provisioning */
-               res.freq = p2p_channel_to_freq(p2p->cfg->country,
-                                              p2p->op_reg_class,
+               res.freq = p2p_channel_to_freq(p2p->op_reg_class,
                                               p2p->op_channel);
                os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
                res.ssid_len = p2p->ssid_len;
@@ -1382,8 +1529,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
                        int freq;
                        if (freqs + 1 == P2P_MAX_CHANNELS)
                                break;
-                       freq = p2p_channel_to_freq(peer->country, c->reg_class,
-                                                  c->channel[j]);
+                       freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
                        if (freq < 0)
                                continue;
                        res.freq_list[freqs++] = freq;
@@ -1405,8 +1551,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
                              const u8 *data, size_t len, int rx_freq)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: RX P2P Public Action from " MACSTR, MAC2STR(sa));
+       p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa));
        wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
 
        if (len < 1)
@@ -1442,8 +1587,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
                p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1);
                break;
        default:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported P2P Public Action frame type %d",
+               p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d",
                        data[0]);
                break;
        }
@@ -1518,16 +1662,14 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
        len--;
 
        /* P2P action frame */
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: RX P2P Action from " MACSTR, MAC2STR(sa));
+       p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
        wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len);
 
        if (len < 1)
                return;
        switch (data[0]) {
        case P2P_NOA:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Received P2P Action - Notice of Absence");
+               p2p_dbg(p2p, "Received P2P Action - Notice of Absence");
                /* TODO */
                break;
        case P2P_PRESENCE_REQ:
@@ -1540,8 +1682,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
                p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq);
                break;
        default:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Received P2P Action - unknown type %u", data[0]);
+               p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]);
                break;
        }
 }
@@ -1613,17 +1754,20 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
 
        if (msg.listen_channel) {
                os_memcpy(dev->country, msg.listen_channel, 3);
-               dev->listen_freq = p2p_channel_to_freq(dev->country,
-                                                      msg.listen_channel[3],
+               dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
                                                       msg.listen_channel[4]);
        }
 
-       p2p_copy_wps_info(dev, 1, &msg);
+       p2p_copy_wps_info(p2p, dev, 1, &msg);
+
+       if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+       }
 
        p2p_parse_free(&msg);
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Created device entry based on Probe Req: " MACSTR
+       p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR
                " dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d",
                MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
                dev->info.group_capab, dev->info.device_name,
@@ -1717,16 +1861,34 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
 {
        struct wpabuf *buf;
        u8 *len;
+       int pw_id = -1;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_probe_resp)
+               extra = wpabuf_len(p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(1000);
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
-       p2p_build_wps_ie(p2p, buf, DEV_PW_DEFAULT, 1);
+       if (p2p->go_neg_peer) {
+               /* Advertise immediate availability of WPS credential */
+               pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
+       }
+
+       p2p_build_wps_ie(p2p, buf, pw_id, 1);
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_probe_resp)
+               wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
 
        /* P2P IE */
        len = p2p_buf_add_ie_hdr(buf);
-       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        if (p2p->ext_listen_interval)
                p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
                                              p2p->ext_listen_interval);
@@ -1737,42 +1899,9 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
 }
 
 
-static int is_11b(u8 rate)
-{
-       return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
-}
-
-
-static int supp_rates_11b_only(struct ieee802_11_elems *elems)
-{
-       int num_11b = 0, num_others = 0;
-       int i;
-
-       if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
-               return 0;
-
-       for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
-               if (is_11b(elems->supp_rates[i]))
-                       num_11b++;
-               else
-                       num_others++;
-       }
-
-       for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
-            i++) {
-               if (is_11b(elems->ext_supp_rates[i]))
-                       num_11b++;
-               else
-                       num_others++;
-       }
-
-       return num_11b > 0 && num_others == 0;
-}
-
-
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
-                           const u8 *dst, const u8 *bssid, const u8 *ie,
-                           size_t ie_len)
+static enum p2p_probe_req_status
+p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+               const u8 *bssid, const u8 *ie, size_t ie_len)
 {
        struct ieee802_11_elems elems;
        struct wpabuf *buf;
@@ -1782,55 +1911,55 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
 
        if (!p2p->in_listen || !p2p->drv_in_listen) {
                /* not in Listen state - ignore Probe Request */
-               return;
+               return P2P_PREQ_NOT_LISTEN;
        }
 
        if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
            ParseFailed) {
                /* Ignore invalid Probe Request frames */
-               return;
+               return P2P_PREQ_MALFORMED;
        }
 
        if (elems.p2p == NULL) {
                /* not a P2P probe - ignore it */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        if (dst && !is_broadcast_ether_addr(dst) &&
            os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
                /* Not sent to the broadcast address or our P2P Device Address
                 */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (bssid && !is_broadcast_ether_addr(bssid)) {
                /* Not sent to the Wildcard BSSID */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
            os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
            0) {
                /* not using P2P Wildcard SSID - ignore */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (supp_rates_11b_only(&elems)) {
                /* Indicates support for 11b rates only */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        os_memset(&msg, 0, sizeof(msg));
        if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
                /* Could not parse P2P attributes */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        if (msg.device_id &&
-           os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+           os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
                /* Device ID did not match */
                p2p_parse_free(&msg);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        /* Check Requested Device Type match */
@@ -1838,15 +1967,16 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
            !p2p_match_dev_type(p2p, msg.wps_attributes)) {
                /* No match with Requested Device Type */
                p2p_parse_free(&msg);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
        p2p_parse_free(&msg);
 
-       if (!p2p->cfg->send_probe_resp)
-               return; /* Response generated elsewhere */
+       if (!p2p->cfg->send_probe_resp) {
+               /* Response generated elsewhere */
+               return P2P_PREQ_NOT_PROCESSED;
+       }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Reply to P2P Probe Request in Listen state");
+       p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state");
 
        /*
         * We do not really have a specific BSS that this frame is advertising,
@@ -1856,12 +1986,12 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
         */
        ies = p2p_build_probe_resp_ies(p2p);
        if (ies == NULL)
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
 
        buf = wpabuf_alloc(200 + wpabuf_len(ies));
        if (buf == NULL) {
                wpabuf_free(ies);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        resp = NULL;
@@ -1870,8 +2000,17 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
        resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
                                           (WLAN_FC_STYPE_PROBE_RESP << 4));
        os_memcpy(resp->da, addr, ETH_ALEN);
+#ifdef TIZEN_EXT_P2P
+       os_memcpy(resp->sa, p2p->cfg->own_addr, ETH_ALEN);
+       os_memcpy(resp->bssid, p2p->cfg->own_addr, ETH_ALEN);
+#else
+       /*
+        * A P2P Device in the Listen State shall set the Source Address and
+        * BSSID to its P2P Device Address (Spec page 26)
+        */
        os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
        os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+#endif
        resp->u.probe_resp.beacon_int = host_to_le16(100);
        /* hardware or low-level driver will setup seq_ctrl and timestamp */
        resp->u.probe_resp.capab_info =
@@ -1904,26 +2043,31 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
        p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
 
        wpabuf_free(buf);
+
+       return P2P_PREQ_NOT_PROCESSED;
 }
 
 
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-                    const u8 *bssid, const u8 *ie, size_t ie_len)
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+                const u8 *bssid, const u8 *ie, size_t ie_len)
 {
+       enum p2p_probe_req_status res;
+
        p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
-       p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+       res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
 
        if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
            p2p->go_neg_peer &&
            os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
-           == 0) {
+           == 0 &&
+           !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
                /* Received a Probe Request from GO Negotiation peer */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Found GO Negotiation peer - try to start GO "
-                       "negotiation from timeout");
+               p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
+               eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
                eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
-               return 1;
+               return P2P_PREQ_PROCESSED;
        }
 
        if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
@@ -1931,14 +2075,12 @@ int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
            os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
            == 0) {
                /* Received a Probe Request from Invite peer */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Found Invite peer - try to start Invite from "
-                       "timeout");
+               p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
                eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
-               return 1;
+               return P2P_PREQ_PROCESSED;
        }
 
-       return 0;
+       return res;
 }
 
 
@@ -2000,20 +2142,31 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
        struct p2p_device *peer;
        size_t tmplen;
        int res;
+       size_t extra = 0;
 
        if (!p2p_group)
                return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_assoc_req)
+               extra = wpabuf_len(p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        /*
         * (Re)Association Request - P2P IE
         * P2P Capability attribute (shall be present)
         * Extended Listen Timing (may be present)
         * P2P Device Info attribute (shall be present)
         */
-       tmp = wpabuf_alloc(200);
+       tmp = wpabuf_alloc(200 + extra);
        if (tmp == NULL)
                return -1;
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_assoc_req)
+               wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
 
        lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2052,6 +2205,40 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
 }
 
 
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
+{
+       struct p2p_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p_ie, &msg))
+               return -1;
+
+       if (msg.p2p_device_addr) {
+               os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+               return 0;
+       } else if (msg.device_id) {
+               os_memcpy(dev_addr, msg.device_id, ETH_ALEN);
+               return 0;
+       }
+       return -1;
+}
+
+
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
+{
+       struct wpabuf *p2p_ie;
+       int ret;
+
+       p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+                                            P2P_IE_VENDOR_TYPE);
+       if (p2p_ie == NULL)
+               return -1;
+       ret = p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr);
+       wpabuf_free(p2p_ie);
+       return ret;
+}
+
+
 static void p2p_clear_go_neg(struct p2p_data *p2p)
 {
        p2p->go_neg_peer = NULL;
@@ -2063,24 +2250,20 @@ static void p2p_clear_go_neg(struct p2p_data *p2p)
 void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
 {
        if (p2p->go_neg_peer == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No pending Group Formation - "
-                       "ignore WPS registration success notification");
+               p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification");
                return; /* No pending Group Formation */
        }
 
        if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) !=
            0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore WPS registration success notification "
-                       "for " MACSTR " (GO Negotiation peer " MACSTR ")",
+               p2p_dbg(p2p, "Ignore WPS registration success notification for "
+                       MACSTR " (GO Negotiation peer " MACSTR ")",
                        MAC2STR(mac_addr),
                        MAC2STR(p2p->go_neg_peer->intended_addr));
                return; /* Ignore unexpected peer address */
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Group Formation completed successfully with " MACSTR,
+       p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR,
                MAC2STR(mac_addr));
 
        p2p_clear_go_neg(p2p);
@@ -2090,14 +2273,11 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
 void p2p_group_formation_failed(struct p2p_data *p2p)
 {
        if (p2p->go_neg_peer == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No pending Group Formation - "
-                       "ignore group formation failure notification");
+               p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification");
                return; /* No pending Group Formation */
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Group Formation failed with " MACSTR,
+       p2p_dbg(p2p, "Group Formation failed with " MACSTR,
                MAC2STR(p2p->go_neg_peer->intended_addr));
 
        p2p_clear_go_neg(p2p);
@@ -2126,9 +2306,20 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
                p2p->cfg->model_number = os_strdup(cfg->model_number);
        if (cfg->serial_number)
                p2p->cfg->serial_number = os_strdup(cfg->serial_number);
+       if (cfg->pref_chan) {
+               p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *
+                                               sizeof(struct p2p_channel));
+               if (p2p->cfg->pref_chan) {
+                       os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,
+                                 cfg->num_pref_chan *
+                                 sizeof(struct p2p_channel));
+               } else
+                       p2p->cfg->num_pref_chan = 0;
+       }
 
        p2p->min_disc_int = 1;
        p2p->max_disc_int = 3;
+       p2p->max_disc_tu = -1;
 
        os_get_random(&p2p->next_tie_breaker, 1);
        p2p->next_tie_breaker &= 0x01;
@@ -2144,15 +2335,37 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
        eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
                               p2p_expiration_timeout, p2p, NULL);
 
+       p2p->go_timeout = 100;
+       p2p->client_timeout = 20;
+
        return p2p;
 }
 
 
 void p2p_deinit(struct p2p_data *p2p)
 {
+#if defined TIZEN_EXT_P2P
+       if (p2p == NULL)
+               return;
+#endif
+#ifdef CONFIG_WIFI_DISPLAY
+       wpabuf_free(p2p->wfd_ie_beacon);
+       wpabuf_free(p2p->wfd_ie_probe_req);
+       wpabuf_free(p2p->wfd_ie_probe_resp);
+       wpabuf_free(p2p->wfd_ie_assoc_req);
+       wpabuf_free(p2p->wfd_ie_invitation);
+       wpabuf_free(p2p->wfd_ie_prov_disc_req);
+       wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+       wpabuf_free(p2p->wfd_ie_go_neg);
+       wpabuf_free(p2p->wfd_dev_info);
+       wpabuf_free(p2p->wfd_assoc_bssid);
+       wpabuf_free(p2p->wfd_coupled_sink_info);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
        eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
        eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+       eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
        p2p_flush(p2p);
        p2p_free_req_dev_types(p2p);
        os_free(p2p->cfg->dev_name);
@@ -2160,6 +2373,7 @@ void p2p_deinit(struct p2p_data *p2p)
        os_free(p2p->cfg->model_name);
        os_free(p2p->cfg->model_number);
        os_free(p2p->cfg->serial_number);
+       os_free(p2p->cfg->pref_chan);
        os_free(p2p->groups);
        wpabuf_free(p2p->sd_resp);
        os_free(p2p->after_scan_tx);
@@ -2171,11 +2385,7 @@ void p2p_deinit(struct p2p_data *p2p)
 void p2p_flush(struct p2p_data *p2p)
 {
        struct p2p_device *dev, *prev;
-       p2p_clear_timeout(p2p);
-       p2p_set_state(p2p, P2P_IDLE);
-       p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
-       p2p->go_neg_peer = NULL;
-       eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+       p2p_stop_find(p2p);
        dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
                              list) {
                dl_list_del(&dev->list);
@@ -2195,8 +2405,7 @@ int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
        if (dev == NULL)
                return -1;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR,
-               MAC2STR(addr));
+       p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
 
        if (p2p->go_neg_peer == dev)
                p2p->go_neg_peer = NULL;
@@ -2368,8 +2577,7 @@ void p2p_continue_find(struct p2p_data *p2p)
                                break;
                } else if (dev->req_config_methods &&
                           !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-                               "pending Provision Discovery Request to "
+                       p2p_dbg(p2p, "Send pending Provision Discovery Request to "
                                MACSTR " (config methods 0x%x)",
                                MAC2STR(dev->info.p2p_device_addr),
                                dev->req_config_methods);
@@ -2378,14 +2586,13 @@ void p2p_continue_find(struct p2p_data *p2p)
                }
        }
 
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 1);
 }
 
 
 static void p2p_sd_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Service Discovery Query TX callback: success=%d",
+       p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d",
                success);
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
@@ -2399,8 +2606,7 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
        }
 
        if (p2p->sd_peer == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No SD peer entry known");
+               p2p_dbg(p2p, "No SD peer entry known");
                p2p_continue_find(p2p);
                return;
        }
@@ -2424,8 +2630,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
 
        /*
         * Retry the prov disc req attempt only for the peer that the user had
-        * requested for and provided a join has not been initiated on it
-        * in the meantime.
+        * requested.
         */
 
        dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
@@ -2434,15 +2639,13 @@ static void p2p_retry_pd(struct p2p_data *p2p)
                        continue;
                if (!dev->req_config_methods)
                        continue;
-               if (dev->flags & P2P_DEV_PD_FOR_JOIN)
-                       continue;
 
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-                       "pending Provision Discovery Request to "
+               p2p_dbg(p2p, "Send pending Provision Discovery Request to "
                        MACSTR " (config methods 0x%x)",
                        MAC2STR(dev->info.p2p_device_addr),
                        dev->req_config_methods);
-               p2p_send_prov_disc_req(p2p, dev, 0, 0);
+               p2p_send_prov_disc_req(p2p, dev,
+                                      dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
                return;
        }
 }
@@ -2450,8 +2653,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
 
 static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Provision Discovery Request TX callback: success=%d",
+       p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d",
                success);
 
        /*
@@ -2467,7 +2669,13 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
        if (!success) {
                p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
-               if (p2p->state != P2P_IDLE)
+               if (p2p->user_initiated_pd &&
+                   (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY))
+               {
+                       /* Retry request from timeout to avoid busy loops */
+                       p2p->pending_action_state = P2P_PENDING_PD;
+                       p2p_set_timeout(p2p, 0, 50000);
+               } else if (p2p->state != P2P_IDLE)
                        p2p_continue_find(p2p);
                else if (p2p->user_initiated_pd) {
                        p2p->pending_action_state = P2P_PENDING_PD;
@@ -2493,20 +2701,26 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 
 
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-                        int level, const u8 *ies, size_t ies_len)
+                        struct os_time *rx_time, int level, const u8 *ies,
+                        size_t ies_len)
 {
-       p2p_add_device(p2p, bssid, freq, level, ies, ies_len);
-
-       if (p2p->go_neg_peer && p2p->state == P2P_SEARCH &&
-           os_memcmp(p2p->go_neg_peer->info.p2p_device_addr, bssid, ETH_ALEN)
-           == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Found GO Negotiation peer - try to start GO "
-                       "negotiation");
-               p2p_connect_send(p2p, p2p->go_neg_peer);
-               return 1;
+       if (os_time_before(rx_time, &p2p->find_start)) {
+               /*
+                * The driver may have cached (e.g., in cfg80211 BSS table) the
+                * scan results for relatively long time. To avoid reporting
+                * stale information, update P2P peers only based on results
+                * that have based on frames received after the last p2p_find
+                * operation was started.
+                */
+               p2p_dbg(p2p, "Ignore old scan result for " MACSTR
+                       " (rx_time=%u.%06u)",
+                       MAC2STR(bssid), (unsigned int) rx_time->sec,
+                       (unsigned int) rx_time->usec);
+               return 0;
        }
 
+       p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
+
        return 0;
 }
 
@@ -2514,8 +2728,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
 void p2p_scan_res_handled(struct p2p_data *p2p)
 {
        if (!p2p->p2p_scan_running) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan was not "
-                       "running, but scan results received");
+               p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
        }
        p2p->p2p_scan_running = 0;
        eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -2527,10 +2740,20 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
 }
 
 
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies)
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
 {
-       u8 *len = p2p_buf_add_ie_hdr(ies);
-       p2p_buf_add_capability(ies, p2p->dev_capab, 0);
+       u8 *len;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_probe_req)
+               wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       len = p2p_buf_add_ie_hdr(ies);
+       p2p_buf_add_capability(ies, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+       if (dev_id)
+               p2p_buf_add_device_id(ies, dev_id);
        if (p2p->cfg->reg_class && p2p->cfg->channel)
                p2p_buf_add_listen_channel(ies, p2p->cfg->country,
                                           p2p->cfg->reg_class,
@@ -2545,7 +2768,14 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies)
 
 size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
 {
-       return 100;
+       size_t len = 100;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p && p2p->wfd_ie_probe_req)
+               len += wpabuf_len(p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       return len;
 }
 
 
@@ -2558,31 +2788,29 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
 static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
 {
        struct p2p_device *dev = p2p->go_neg_peer;
+       int timeout;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation Request TX callback: success=%d",
-               success);
+       p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success);
 
        if (dev == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No pending GO Negotiation");
+               p2p_dbg(p2p, "No pending GO Negotiation");
                return;
        }
 
        if (success) {
-               dev->go_neg_req_sent++;
                if (dev->flags & P2P_DEV_USER_REJECTED) {
                        p2p_set_state(p2p, P2P_IDLE);
                        return;
                }
+       } else if (dev->go_neg_req_sent) {
+               /* Cancel the increment from p2p_connect_send() on failure */
+               dev->go_neg_req_sent--;
        }
 
        if (!success &&
            (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
            !is_zero_ether_addr(dev->member_in_go_dev)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Peer " MACSTR " did not acknowledge request - "
-                       "try to use device discoverability through its GO",
+               p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO",
                        MAC2STR(dev->info.p2p_device_addr));
                p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
                p2p_send_dev_disc_req(p2p, dev);
@@ -2594,34 +2822,49 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
         * channel.
         */
        p2p_set_state(p2p, P2P_CONNECT);
-       p2p_set_timeout(p2p, 0, 100000);
+       timeout = success ? 500000 : 100000;
+       if (!success && p2p->go_neg_peer &&
+           (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+               unsigned int r;
+               /*
+                * Peer is expected to wait our response and we will skip the
+                * listen phase. Add some randomness to the wait time here to
+                * make it less likely to hit cases where we could end up in
+                * sync with peer not listening.
+                */
+               os_get_random((u8 *) &r, sizeof(r));
+               timeout += r % 100000;
+       }
+       p2p_set_timeout(p2p, 0, timeout);
 }
 
 
 static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation Response TX callback: success=%d",
+       p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d",
                success);
        if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore TX callback event - GO Negotiation is "
-                       "not running anymore");
+               p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore");
                return;
        }
        p2p_set_state(p2p, P2P_CONNECT);
-       p2p_set_timeout(p2p, 0, 100000);
+       p2p_set_timeout(p2p, 0, 500000);
 }
 
 
-static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
+                                      const u8 *addr)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation Response (failure) TX callback: "
-               "success=%d", success);
+       p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
        if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
                p2p_go_neg_failed(p2p, p2p->go_neg_peer,
                                  p2p->go_neg_peer->status);
+       } else if (success) {
+               struct p2p_device *dev;
+               dev = p2p_get_device(p2p, addr);
+               if (dev &&
+                   dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+                       dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
        }
 }
 
@@ -2631,9 +2874,7 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
 {
        struct p2p_device *dev;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation Confirm TX callback: result=%d",
-               result);
+       p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
        if (result == P2P_SEND_ACTION_FAILED) {
                p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
@@ -2650,10 +2891,7 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
                 * peer did indeed receive the frame, continue regardless of
                 * the TX status.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Assume GO Negotiation Confirm TX was actually "
-                       "received by the peer even though Ack was not "
-                       "reported");
+               p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
        }
 
        dev = p2p->go_neg_peer;
@@ -2671,8 +2909,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
        enum p2p_pending_action_state state;
        int success;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Action frame TX callback (state=%d freq=%u dst=" MACSTR
+       p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
                " src=" MACSTR " bssid=" MACSTR " result=%d",
                p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
                MAC2STR(bssid), result);
@@ -2681,6 +2918,16 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
        switch (state) {
        case P2P_NO_PENDING_ACTION:
+               if (p2p->after_scan_tx_in_progress) {
+                       p2p->after_scan_tx_in_progress = 0;
+                       if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
+                           p2p_run_after_scan(p2p))
+                               break;
+                       if (p2p->state == P2P_SEARCH) {
+                               p2p_dbg(p2p, "Continue find after after_scan_tx completion");
+                               p2p_continue_find(p2p);
+                       }
+               }
                break;
        case P2P_PENDING_GO_NEG_REQUEST:
                p2p_go_neg_req_cb(p2p, success);
@@ -2689,7 +2936,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                p2p_go_neg_resp_cb(p2p, success);
                break;
        case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
-               p2p_go_neg_resp_failure_cb(p2p, success);
+               p2p_go_neg_resp_failure_cb(p2p, success, dst);
                break;
        case P2P_PENDING_GO_NEG_CONFIRM:
                p2p_go_neg_conf_cb(p2p, result);
@@ -2716,6 +2963,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                p2p_go_disc_req_cb(p2p, success);
                break;
        }
+
+       p2p->after_scan_tx_in_progress = 0;
 }
 
 
@@ -2723,23 +2972,18 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
                   unsigned int duration)
 {
        if (freq == p2p->pending_client_disc_freq) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Client discoverability remain-awake completed");
+               p2p_dbg(p2p, "Client discoverability remain-awake completed");
                p2p->pending_client_disc_freq = 0;
                return;
        }
 
        if (freq != p2p->pending_listen_freq) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected listen callback for freq=%u "
-                       "duration=%u (pending_listen_freq=%u)",
+               p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)",
                        freq, duration, p2p->pending_listen_freq);
                return;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Starting Listen timeout(%u,%u) on freq=%u based on "
-               "callback",
+       p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback",
                p2p->pending_listen_sec, p2p->pending_listen_usec,
                p2p->pending_listen_freq);
        p2p->in_listen = 1;
@@ -2760,17 +3004,14 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
 
 int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver ended Listen "
-               "state (freq=%u)", freq);
+       p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq);
        p2p->drv_in_listen = 0;
        if (p2p->in_listen)
                return 0; /* Internal timeout will trigger the next step */
 
        if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
                if (p2p->go_neg_peer->connect_reqs >= 120) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Timeout on sending GO Negotiation "
-                               "Request without getting response");
+                       p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
                        p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
                        return 0;
                }
@@ -2779,6 +3020,35 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
                p2p_connect_send(p2p, p2p->go_neg_peer);
                return 1;
        } else if (p2p->state == P2P_SEARCH) {
+               if (p2p->p2p_scan_running) {
+                        /*
+                         * Search is already in progress. This can happen if
+                         * an Action frame RX is reported immediately after
+                         * the end of a remain-on-channel operation and the
+                         * response frame to that is sent using an offchannel
+                         * operation while in p2p_find. Avoid an attempt to
+                         * restart a scan here.
+                         */
+                       p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one");
+                       return 1;
+               }
+               if (p2p->pending_listen_freq) {
+                       /*
+                        * Better wait a bit if the driver is unable to start
+                        * offchannel operation for some reason. p2p_search()
+                        * will be started from internal timeout.
+                        */
+                       p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop");
+                       p2p_set_timeout(p2p, 0, 100000);
+                       return 1;
+               }
+               if (p2p->search_delay) {
+                       p2p_dbg(p2p, "Delay search operation by %u ms",
+                               p2p->search_delay);
+                       p2p_set_timeout(p2p, p2p->search_delay / 1000,
+                                       (p2p->search_delay % 1000) * 1000);
+                       return 1;
+               }
                p2p_search(p2p);
                return 1;
        }
@@ -2790,8 +3060,22 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
 static void p2p_timeout_connect(struct p2p_data *p2p)
 {
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       if (p2p->go_neg_peer &&
+           (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
+               p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
+               p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+               return;
+       }
+       if (p2p->go_neg_peer &&
+           (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
+           p2p->go_neg_peer->connect_reqs < 120) {
+               p2p_dbg(p2p, "Peer expected to wait our response - skip listen");
+               p2p_connect_send(p2p, p2p->go_neg_peer);
+               return;
+       }
+
        p2p_set_state(p2p, P2P_CONNECT_LISTEN);
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
@@ -2799,16 +3083,12 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
 {
        if (p2p->go_neg_peer) {
                if (p2p->drv_in_listen) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is "
-                               "still in Listen state; wait for it to "
-                               "complete");
+                       p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete");
                        return;
                }
 
                if (p2p->go_neg_peer->connect_reqs >= 120) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Timeout on sending GO Negotiation "
-                               "Request without getting response");
+                       p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
                        p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
                        return;
                }
@@ -2837,32 +3117,26 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
        struct p2p_device *dev = p2p->go_neg_peer;
 
        if (dev == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown GO Neg peer - stop GO Neg wait");
+               p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
                return;
        }
 
        dev->wait_count++;
        if (dev->wait_count >= 120) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Timeout on waiting peer to become ready for GO "
-                       "Negotiation");
+               p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation");
                p2p_go_neg_failed(p2p, dev, -1);
                return;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Go to Listen state while waiting for the peer to become "
-               "ready for GO Negotiation");
+       p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
        p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
 static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Service Discovery Query timeout");
+       p2p_dbg(p2p, "Service Discovery Query timeout");
        if (p2p->sd_peer) {
                p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
                p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
@@ -2874,8 +3148,7 @@ static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
 
 static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Provision Discovery Request timeout");
+       p2p_dbg(p2p, "Provision Discovery Request timeout");
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
        p2p_continue_find(p2p);
 }
@@ -2893,16 +3166,29 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
        if (!p2p->user_initiated_pd)
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: User initiated Provision Discovery Request timeout");
+       p2p_dbg(p2p, "User initiated Provision Discovery Request timeout");
 
        if (p2p->pd_retries) {
                p2p->pd_retries--;
                p2p_retry_pd(p2p);
        } else {
+               struct p2p_device *dev;
+               int for_join = 0;
+
+               dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+                       if (os_memcmp(p2p->pending_pd_devaddr,
+                                     dev->info.p2p_device_addr, ETH_ALEN) != 0)
+                               continue;
+                       if (dev->req_config_methods &&
+                           (dev->flags & P2P_DEV_PD_FOR_JOIN))
+                               for_join = 1;
+               }
+
                if (p2p->cfg->prov_disc_fail)
                        p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
                                                 p2p->pending_pd_devaddr,
+                                                for_join ?
+                                                P2P_PROV_DISC_TIMEOUT_JOIN :
                                                 P2P_PROV_DISC_TIMEOUT);
                p2p_reset_pending_pd(p2p);
        }
@@ -2918,12 +3204,11 @@ static void p2p_timeout_invite(struct p2p_data *p2p)
                 * Better remain on operating channel instead of listen channel
                 * when running a group.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Inviting in "
-                       "active GO role - wait on operating channel");
+               p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
                p2p_set_timeout(p2p, 0, 100000);
                return;
        }
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
@@ -2935,11 +3220,11 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p)
                                p2p->invite_go_dev_addr);
        } else {
                if (p2p->invite_peer) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Invitation Request retry limit reached");
+                       p2p_dbg(p2p, "Invitation Request retry limit reached");
                        if (p2p->cfg->invitation_result)
                                p2p->cfg->invitation_result(
-                                       p2p->cfg->cb_ctx, -1, NULL);
+                                       p2p->cfg->cb_ctx, -1, NULL, NULL,
+                                       p2p->invite_peer->info.p2p_device_addr);
                }
                p2p_set_state(p2p, P2P_IDLE);
        }
@@ -2950,8 +3235,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct p2p_data *p2p = eloop_ctx;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Timeout (state=%s)",
-               p2p_state_txt(p2p->state));
+       p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
 
        p2p->in_listen = 0;
 
@@ -2965,6 +3249,15 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
                /* Check if we timed out waiting for PD req */
                if (p2p->pending_action_state == P2P_PENDING_PD)
                        p2p_timeout_prov_disc_req(p2p);
+               if (p2p->search_delay && !p2p->in_search_delay) {
+                       p2p_dbg(p2p, "Delay search operation by %u ms",
+                               p2p->search_delay);
+                       p2p->in_search_delay = 1;
+                       p2p_set_timeout(p2p, p2p->search_delay / 1000,
+                                       (p2p->search_delay % 1000) * 1000);
+                       break;
+               }
+               p2p->in_search_delay = 0;
                p2p_search(p2p);
                break;
        case P2P_CONNECT:
@@ -2981,9 +3274,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
                        p2p_timeout_prov_disc_req(p2p);
 
                if (p2p->ext_listen_only) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Extended Listen Timing - Listen State "
-                               "completed");
+                       p2p_dbg(p2p, "Extended Listen Timing - Listen State completed");
                        p2p->ext_listen_only = 0;
                        p2p_set_state(p2p, P2P_IDLE);
                }
@@ -3010,6 +3301,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
                break;
        case P2P_SEARCH_WHEN_READY:
                break;
+       case P2P_CONTINUE_SEARCH_WHEN_READY:
+               break;
        }
 }
 
@@ -3019,11 +3312,10 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
        struct p2p_device *dev;
 
        dev = p2p_get_device(p2p, peer_addr);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Local request to reject "
-               "connection attempts by peer " MACSTR, MAC2STR(peer_addr));
+       p2p_dbg(p2p, "Local request to reject connection attempts by peer "
+               MACSTR, MAC2STR(peer_addr));
        if (dev == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
-                       " unknown", MAC2STR(peer_addr));
+               p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr));
                return -1;
        }
        dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -3031,6 +3323,24 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
        return 0;
 }
 
+#ifdef TIZEN_EXT_P2P
+int p2p_reject_connection(struct p2p_data *p2p, const u8 *peer_addr)
+{
+       struct p2p_device *dev;
+
+       dev = p2p_get_device(p2p, peer_addr);
+       p2p_dbg(p2p, "P2P: Local request to reject connection attempts by peer "
+      MACSTR, MAC2STR(peer_addr));
+       if (dev == NULL) {
+               p2p_dbg(p2p, "P2P: Peer " MACSTR " unknown", MAC2STR(peer_addr));
+               return -1;
+       }
+
+       return p2p_reject_send(p2p, dev);
+}
+#endif
+
+
 
 const char * p2p_wps_method_text(enum p2p_wps_method method)
 {
@@ -3064,14 +3374,10 @@ static const char * p2p_go_state_text(enum p2p_go_state go_state)
 }
 
 
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-                     char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+                                              const u8 *addr, int next)
 {
        struct p2p_device *dev;
-       int res;
-       char *pos, *end;
-       struct os_time now;
-       char devtype[WPS_DEV_TYPE_BUFSIZE];
 
        if (addr)
                dev = p2p_get_device(p2p, addr);
@@ -3085,35 +3391,37 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
        }
 
        if (dev == NULL)
+               return NULL;
+
+       return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+                         char *buf, size_t buflen)
+{
+       struct p2p_device *dev;
+       int res;
+       char *pos, *end;
+       struct os_time now;
+
+       if (info == NULL)
                return -1;
 
+       dev = (struct p2p_device *) (((u8 *) info) -
+                                    offsetof(struct p2p_device, info));
+
        pos = buf;
        end = buf + buflen;
 
-       res = os_snprintf(pos, end - pos, MACSTR "\n",
-                         MAC2STR(dev->info.p2p_device_addr));
-       if (res < 0 || res >= end - pos)
-               return pos - buf;
-       pos += res;
-
        os_get_time(&now);
        res = os_snprintf(pos, end - pos,
                          "age=%d\n"
                          "listen_freq=%d\n"
-                         "level=%d\n"
                          "wps_method=%s\n"
                          "interface_addr=" MACSTR "\n"
                          "member_in_go_dev=" MACSTR "\n"
                          "member_in_go_iface=" 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"
                          "go_neg_req_sent=%d\n"
                          "go_state=%s\n"
                          "dialog_token=%u\n"
@@ -3127,21 +3435,10 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
                          "invitation_reqs=%u\n",
                          (int) (now.sec - dev->last_seen.sec),
                          dev->listen_freq,
-                         dev->info.level,
                          p2p_wps_method_text(dev->wps_method),
                          MAC2STR(dev->interface_addr),
                          MAC2STR(dev->member_in_go_dev),
                          MAC2STR(dev->member_in_go_iface),
-                         wps_dev_type_bin2str(dev->info.pri_dev_type,
-                                              devtype, sizeof(devtype)),
-                         dev->info.device_name,
-                         dev->info.manufacturer,
-                         dev->info.model_name,
-                         dev->info.model_number,
-                         dev->info.serial_number,
-                         dev->info.config_methods,
-                         dev->info.dev_capab,
-                         dev->info.group_capab,
                          dev->go_neg_req_sent,
                          p2p_go_state_text(dev->go_state),
                          dev->dialog_token,
@@ -3206,19 +3503,41 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
                pos += res;
        }
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (dev->info.wfd_subelems) {
+               res = os_snprintf(pos, end - pos, "wfd_subelems=");
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+
+               pos += wpa_snprintf_hex(pos, end - pos,
+                                       wpabuf_head(dev->info.wfd_subelems),
+                                       wpabuf_len(dev->info.wfd_subelems));
+
+               res = os_snprintf(pos, end - pos, "\n");
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return pos - buf;
 }
 
 
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+       return p2p_get_device(p2p, addr) != NULL;
+}
+
+
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
 {
        if (enabled) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
-                       "discoverability enabled");
+               p2p_dbg(p2p, "Client discoverability enabled");
                p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
-                       "discoverability disabled");
+               p2p_dbg(p2p, "Client discoverability disabled");
                p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
        }
 }
@@ -3267,9 +3586,9 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
 {
        struct wpabuf *req;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send Presence Request to "
-               "GO " MACSTR " (own interface " MACSTR ") freq=%u dur1=%u "
-               "int1=%u dur2=%u int2=%u",
+       p2p_dbg(p2p, "Send Presence Request to GO " MACSTR
+               " (own interface " MACSTR ") freq=%u dur1=%u int1=%u "
+               "dur2=%u int2=%u",
                MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
                freq, duration1, interval1, duration2, interval2);
 
@@ -3282,8 +3601,7 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
        if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr,
                            go_interface_addr,
                            wpabuf_head(req), wpabuf_len(req), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
        wpabuf_free(req);
 
@@ -3329,8 +3647,7 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
        u8 noa[50];
        int noa_len;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received P2P Action - P2P Presence Request");
+       p2p_dbg(p2p, "Received P2P Action - P2P Presence Request");
 
        for (g = 0; g < p2p->num_groups; g++) {
                if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]),
@@ -3340,23 +3657,20 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
                }
        }
        if (group == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore P2P Presence Request for unknown group "
+               p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group "
                        MACSTR, MAC2STR(da));
                return;
        }
 
        if (p2p_parse(data, len, &msg) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to parse P2P Presence Request");
+               p2p_dbg(p2p, "Failed to parse P2P Presence Request");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
        parsed = 1;
 
        if (msg.noa == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No NoA attribute in P2P Presence Request");
+               p2p_dbg(p2p, "No NoA attribute in P2P Presence Request");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
@@ -3380,8 +3694,7 @@ fail:
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
        if (p2p_send_action(p2p, rx_freq, sa, da, da,
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
        wpabuf_free(resp);
 }
@@ -3392,33 +3705,27 @@ static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
 {
        struct p2p_message msg;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received P2P Action - P2P Presence Response");
+       p2p_dbg(p2p, "Received P2P Action - P2P Presence Response");
 
        if (p2p_parse(data, len, &msg) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to parse P2P Presence Response");
+               p2p_dbg(p2p, "Failed to parse P2P Presence Response");
                return;
        }
 
        if (msg.status == NULL || msg.noa == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Status or NoA attribute in P2P Presence "
-                       "Response");
+               p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response");
                p2p_parse_free(&msg);
                return;
        }
 
        if (*msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: P2P Presence Request was rejected: status %u",
+               p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
                        *msg.status);
                p2p_parse_free(&msg);
                return;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: P2P Presence Request was accepted");
+       p2p_dbg(p2p, "P2P Presence Request was accepted");
        wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
                    msg.noa, msg.noa_len);
        /* TODO: process NoA */
@@ -3444,25 +3751,20 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
                 * running at an inconvenient time. As a workaround, allow new
                 * Extended Listen operation to be started.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Previous "
-                       "Extended Listen operation had not been completed - "
-                       "try again");
+               p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again");
                p2p->ext_listen_only = 0;
                p2p_set_state(p2p, P2P_IDLE);
        }
 
        if (p2p->state != P2P_IDLE) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip Extended "
-                       "Listen timeout in active state (%s)",
-                       p2p_state_txt(p2p->state));
+               p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state));
                return;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Extended Listen timeout");
+       p2p_dbg(p2p, "Extended Listen timeout");
        p2p->ext_listen_only = 1;
        if (p2p_listen(p2p, p2p->ext_listen_period) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
-                       "Listen state for Extended Listen Timing");
+               p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing");
                p2p->ext_listen_only = 0;
        }
 }
@@ -3473,25 +3775,22 @@ int p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
 {
        if (period > 65535 || interval > 65535 || period > interval ||
            (period == 0 && interval > 0) || (period > 0 && interval == 0)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid Extended Listen Timing request: "
-                       "period=%u interval=%u", period, interval);
+               p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u",
+                       period, interval);
                return -1;
        }
 
        eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
 
        if (interval == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Disabling Extended Listen Timing");
+               p2p_dbg(p2p, "Disabling Extended Listen Timing");
                p2p->ext_listen_period = 0;
                p2p->ext_listen_interval = 0;
                return 0;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Enabling Extended Listen Timing: period %u msec, "
-               "interval %u msec", period, interval);
+       p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec",
+               period, interval);
        p2p->ext_listen_period = period;
        p2p->ext_listen_interval = interval;
        p2p->ext_listen_interval_sec = interval / 1000;
@@ -3519,8 +3818,7 @@ void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
        if (msg.minor_reason_code == NULL)
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-               "P2P: Deauthentication notification BSSID " MACSTR
+       p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
                " reason_code=%u minor_reason_code=%u",
                MAC2STR(bssid), reason_code, *msg.minor_reason_code);
 
@@ -3542,8 +3840,7 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
        if (msg.minor_reason_code == NULL)
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-               "P2P: Disassociation notification BSSID " MACSTR
+       p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
                " reason_code=%u minor_reason_code=%u",
                MAC2STR(bssid), reason_code, *msg.minor_reason_code);
 
@@ -3554,12 +3851,10 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
 void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
 {
        if (enabled) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
-                       "Device operations enabled");
+               p2p_dbg(p2p, "Managed P2P Device operations enabled");
                p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
-                       "Device operations disabled");
+               p2p_dbg(p2p, "Managed P2P Device operations disabled");
                p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
        }
 }
@@ -3567,11 +3862,11 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
 
 int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
 {
-       if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+       if (p2p_channel_to_freq(reg_class, channel) < 0)
                return -1;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
-               "reg_class %u channel %u", reg_class, channel);
+       p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
+               reg_class, channel);
        p2p->cfg->reg_class = reg_class;
        p2p->cfg->channel = channel;
 
@@ -3581,7 +3876,7 @@ int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
 
 int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
 {
-       wpa_hexdump_ascii(MSG_DEBUG, "P2P: New SSID postfix", postfix, len);
+       p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
        if (postfix == NULL) {
                p2p->cfg->ssid_postfix_len = 0;
                return 0;
@@ -3597,12 +3892,11 @@ int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
 int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
                         int cfg_op_channel)
 {
-       if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
-           < 0)
+       if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
                return -1;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
-               "reg_class %u channel %u", op_reg_class, op_channel);
+       p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u",
+               op_reg_class, op_channel);
        p2p->cfg->op_reg_class = op_reg_class;
        p2p->cfg->op_channel = op_channel;
        p2p->cfg->cfg_op_channel = cfg_op_channel;
@@ -3610,6 +3904,28 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 }
 
 
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+                     const struct p2p_channel *pref_chan)
+{
+       struct p2p_channel *n;
+
+       if (pref_chan) {
+               n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+               if (n == NULL)
+                       return -1;
+               os_memcpy(n, pref_chan,
+                         num_pref_chan * sizeof(struct p2p_channel));
+       } else
+               n = NULL;
+
+       os_free(p2p->cfg->pref_chan);
+       p2p->cfg->pref_chan = n;
+       p2p->cfg->num_pref_chan = num_pref_chan;
+
+       return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
                           u8 *iface_addr)
 {
@@ -3636,18 +3952,16 @@ void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr)
 {
        os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
        if (is_zero_ether_addr(p2p->peer_filter))
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Disable peer "
-                       "filter");
+               p2p_dbg(p2p, "Disable peer filter");
        else
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer "
-                       "filter for " MACSTR, MAC2STR(p2p->peer_filter));
+               p2p_dbg(p2p, "Enable peer filter for " MACSTR,
+                       MAC2STR(p2p->peer_filter));
 }
 
 
 void p2p_set_cross_connect(struct p2p_data *p2p, int enabled)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s",
-               enabled ? "enabled" : "disabled");
+       p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled");
        if (p2p->cross_connect == enabled)
                return;
        p2p->cross_connect = enabled;
@@ -3668,7 +3982,7 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr)
 
 void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Intra BSS distribution %s",
+       p2p_dbg(p2p, "Intra BSS distribution %s",
                enabled ? "enabled" : "disabled");
        p2p->cfg->p2p_intra_bss = enabled;
 }
@@ -3676,7 +3990,7 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
 
 void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update channel list");
+       p2p_dbg(p2p, "Update channel list");
        os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
 }
 
@@ -3686,11 +4000,9 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                    size_t len, unsigned int wait_time)
 {
        if (p2p->p2p_scan_running) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay Action "
-                       "frame TX until p2p_scan completes");
+               p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
                if (p2p->after_scan_tx) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
-                               "previous pending Action frame TX");
+                       p2p_dbg(p2p, "Dropped previous pending Action frame TX");
                        os_free(p2p->after_scan_tx);
                }
                p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
@@ -3715,14 +4027,21 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
 void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
                           int freq_overall)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d,"
-               "  5 GHz: %d,  overall: %d", freq_24, freq_5, freq_overall);
+       p2p_dbg(p2p, "Best channel: 2.4 GHz: %d,  5 GHz: %d,  overall: %d",
+               freq_24, freq_5, freq_overall);
        p2p->best_freq_24 = freq_24;
        p2p->best_freq_5 = freq_5;
        p2p->best_freq_overall = freq_overall;
 }
 
 
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
+{
+       p2p_dbg(p2p, "Own frequency preference: %d MHz", freq);
+       p2p->own_freq_preference = freq;
+}
+
+
 const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
 {
        if (p2p == NULL || p2p->go_neg_peer == NULL)
@@ -3776,5 +4095,214 @@ int p2p_in_progress(struct p2p_data *p2p)
 {
        if (p2p == NULL)
                return 0;
+       if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
+           p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+               return 2;
        return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
 }
+
+
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+                           u8 client_timeout)
+{
+       if (p2p) {
+               p2p->go_timeout = go_timeout;
+               p2p->client_timeout = client_timeout;
+       }
+}
+
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
+{
+       if (p2p && p2p->search_delay < delay)
+               p2p->search_delay = delay;
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
+{
+       size_t g;
+       struct p2p_group *group;
+
+       for (g = 0; g < p2p->num_groups; g++) {
+               group = p2p->groups[g];
+               p2p_group_update_ies(group);
+       }
+}
+
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_beacon);
+       p2p->wfd_ie_beacon = ie;
+       p2p_update_wfd_ie_groups(p2p);
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_probe_req);
+       p2p->wfd_ie_probe_req = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_probe_resp);
+       p2p->wfd_ie_probe_resp = ie;
+       p2p_update_wfd_ie_groups(p2p);
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_assoc_req);
+       p2p->wfd_ie_assoc_req = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_invitation);
+       p2p->wfd_ie_invitation = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_prov_disc_req);
+       p2p->wfd_ie_prov_disc_req = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+       p2p->wfd_ie_prov_disc_resp = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie)
+{
+       wpabuf_free(p2p->wfd_ie_go_neg);
+       p2p->wfd_ie_go_neg = ie;
+       return 0;
+}
+
+
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+       wpabuf_free(p2p->wfd_dev_info);
+       if (elem) {
+               p2p->wfd_dev_info = wpabuf_dup(elem);
+               if (p2p->wfd_dev_info == NULL)
+                       return -1;
+       } else
+               p2p->wfd_dev_info = NULL;
+
+       return 0;
+}
+
+
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+       wpabuf_free(p2p->wfd_assoc_bssid);
+       if (elem) {
+               p2p->wfd_assoc_bssid = wpabuf_dup(elem);
+               if (p2p->wfd_assoc_bssid == NULL)
+                       return -1;
+       } else
+               p2p->wfd_assoc_bssid = NULL;
+
+       return 0;
+}
+
+
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+                                 const struct wpabuf *elem)
+{
+       wpabuf_free(p2p->wfd_coupled_sink_info);
+       if (elem) {
+               p2p->wfd_coupled_sink_info = wpabuf_dup(elem);
+               if (p2p->wfd_coupled_sink_info == NULL)
+                       return -1;
+       } else
+               p2p->wfd_coupled_sink_info = NULL;
+
+       return 0;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+                    int max_disc_tu)
+{
+       if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0)
+               return -1;
+
+       p2p->min_disc_int = min_disc_int;
+       p2p->max_disc_int = max_disc_int;
+       p2p->max_disc_tu = max_disc_tu;
+       p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d",
+               min_disc_int, max_disc_int, max_disc_tu);
+
+       return 0;
+}
+
+
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[500];
+
+       if (!p2p->cfg->debug_print)
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       buf[sizeof(buf) - 1] = '\0';
+       va_end(ap);
+       p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf);
+}
+
+
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[500];
+
+       if (!p2p->cfg->debug_print)
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       buf[sizeof(buf) - 1] = '\0';
+       va_end(ap);
+       p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf);
+}
+
+
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[500];
+
+       if (!p2p->cfg->debug_print)
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       buf[sizeof(buf) - 1] = '\0';
+       va_end(ap);
+       p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
+}
index 6a640ab..2be73ae 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P module
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef P2P_H
@@ -81,6 +75,8 @@ struct p2p_go_neg_results {
         */
        int freq;
 
+       int ht40;
+
        /**
         * ssid - SSID of the group
         */
@@ -92,6 +88,16 @@ struct p2p_go_neg_results {
        size_t ssid_len;
 
        /**
+        * psk - WPA pre-shared key (256 bits) (GO only)
+        */
+       u8 psk[32];
+
+       /**
+        * psk_set - Whether PSK field is configured (GO only)
+        */
+       int psk_set;
+
+       /**
         * passphrase - WPA2-Personal passphrase for the group (GO only)
         */
        char passphrase[64];
@@ -137,7 +143,6 @@ struct p2p_data;
 enum p2p_scan_type {
        P2P_SCAN_SOCIAL,
        P2P_SCAN_FULL,
-       P2P_SCAN_SPECIFIC,
        P2P_SCAN_SOCIAL_PLUS_ONE
 };
 
@@ -216,12 +221,23 @@ struct p2p_peer_info {
        size_t wps_sec_dev_type_list_len;
 
        struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+       /**
+        * wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
+        */
+       struct wpabuf *wfd_subelems;
 };
 
 enum p2p_prov_disc_status {
        P2P_PROV_DISC_SUCCESS,
        P2P_PROV_DISC_TIMEOUT,
        P2P_PROV_DISC_REJECTED,
+       P2P_PROV_DISC_TIMEOUT_JOIN,
+};
+
+struct p2p_channel {
+       u8 op_class;
+       u8 chan;
 };
 
 /**
@@ -271,6 +287,16 @@ struct p2p_config {
        struct p2p_channels channels;
 
        /**
+        * num_pref_chan - Number of pref_chan entries
+        */
+       unsigned int num_pref_chan;
+
+       /**
+        * pref_chan - Preferred channels for GO Negotiation
+        */
+       struct p2p_channel *pref_chan;
+
+       /**
         * pri_dev_type - Primary Device Type (see WPS)
         */
        u8 pri_dev_type[8];
@@ -290,6 +316,13 @@ struct p2p_config {
         */
        size_t num_sec_dev_types;
 
+#ifdef TIZEN_EXT
+       /**
+        * own_addr - Device Own MAC Address
+        */
+       u8 own_addr[ETH_ALEN];
+#endif
+
        /**
         * dev_addr - P2P Device Address
         */
@@ -340,15 +373,23 @@ struct p2p_config {
        size_t ssid_postfix_len;
 
        /**
-        * msg_ctx - Context to use with wpa_msg() calls
+        * max_listen - Maximum listen duration in ms
         */
-       void *msg_ctx;
+       unsigned int max_listen;
 
        /**
         * cb_ctx - Context to use with callback functions
         */
        void *cb_ctx;
 
+       /**
+        * debug_print - Debug print
+        * @ctx: Callback context from cb_ctx
+        * @level: Debug verbosity level (MSG_*)
+        * @msg: Debug message
+        */
+       void (*debug_print)(void *ctx, int level, const char *msg);
+
 
        /* Callbacks to request lower layer driver operations */
 
@@ -359,14 +400,15 @@ struct p2p_config {
         * @freq: Specific frequency (MHz) to scan or 0 for no restriction
         * @num_req_dev_types: Number of requested device types
         * @req_dev_types: Array containing requested device types
+        * @dev_id: Device ID to search for or %NULL to find all devices
+        * @pw_id: Device Password ID
         * Returns: 0 on success, -1 on failure
         *
         * This callback function is used to request a P2P scan or search
         * operation to be completed. Type type argument specifies which type
         * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
         * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
-        * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
-        * request a scan of a single channel specified by freq.
+        * indicates that all channels are to be scanned.
         * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
         * plus one extra channel specified by freq.
         *
@@ -382,7 +424,7 @@ struct p2p_config {
         */
        int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
                        unsigned int num_req_dev_types,
-                       const u8 *req_dev_types);
+                       const u8 *req_dev_types, const u8 *dev_id, u16 pw_id);
 
        /**
         * send_probe_resp - Transmit a Probe Response frame
@@ -513,6 +555,12 @@ struct p2p_config {
        void (*dev_lost)(void *ctx, const u8 *dev_addr);
 
        /**
+        * find_stopped - Notification of a p2p_find operation stopping
+        * @ctx: Callback context from cb_ctx
+        */
+       void (*find_stopped)(void *ctx);
+
+       /**
         * go_neg_req_rx - Notification of a receive GO Negotiation Request
         * @ctx: Callback context from cb_ctx
         * @src: Source address of the message triggering this notification
@@ -648,6 +696,7 @@ struct p2p_config {
         * @persistent_group: Whether this is an invitation to reinvoke a
         *      persistent group (instead of invitation to join an active
         *      group)
+        * @channels: Available operating channels for the group
         * Returns: Status code (P2P_SC_*)
         *
         * This optional callback can be used to implement persistent reconnect
@@ -668,7 +717,8 @@ struct p2p_config {
        u8 (*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);
+                                int *force_freq, int persistent_group,
+                                const struct p2p_channels *channels);
 
        /**
         * invitation_received - Callback on Invitation Request RX
@@ -697,6 +747,8 @@ struct p2p_config {
         * @ctx: Callback context from cb_ctx
         * @status: Negotiation result (Status Code)
         * @bssid: P2P Group BSSID or %NULL if not received
+        * @channels: Available operating channels for the group
+        * @addr: Peer address
         *
         * This callback is used to indicate result of an Invitation procedure
         * started with a call to p2p_invite(). The indicated status code is
@@ -704,7 +756,18 @@ struct p2p_config {
         * (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
         * local failure in transmitting the Invitation Request.
         */
-       void (*invitation_result)(void *ctx, int status, const u8 *bssid);
+       void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+                                 const struct p2p_channels *channels,
+                                 const u8 *addr);
+
+       /**
+        * go_connected - Check whether we are connected to a GO
+        * @ctx: Callback context from cb_ctx
+        * @dev_addr: P2P Device Address of a GO
+        * Returns: 1 if we are connected as a P2P client to the specified GO
+        * or 0 if not.
+        */
+       int (*go_connected)(void *ctx, const u8 *dev_addr);
 };
 
 
@@ -809,11 +872,14 @@ enum p2p_discovery_type {
  * @req_dev_types: Requested device types array, must be an array
  *     containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no
  *     requested device types.
+ * @dev_id: Device ID to search for or %NULL to find all devices
+ * @search_delay: Extra delay in milliseconds between search iterations
  * Returns: 0 on success, -1 on failure
  */
 int p2p_find(struct p2p_data *p2p, unsigned int timeout,
             enum p2p_discovery_type type,
-            unsigned int num_req_dev_types, const u8 *req_dev_types);
+            unsigned int num_req_dev_types, const u8 *req_dev_types,
+            const u8 *dev_id, unsigned int search_delay);
 
 /**
  * p2p_stop_find - Stop P2P Find (Device Discovery)
@@ -855,12 +921,22 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
  * @persistent_group: Whether to create a persistent group (0 = no, 1 =
  * persistent group without persistent reconnect, 2 = persistent group with
  * persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *     a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pd_before_go_neg: Whether to send Provision Discovery prior to GO
+ *     Negotiation as an interoperability workaround when initiating group
+ *     formation
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *     force_freq == 0)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_connect(struct p2p_data *p2p, 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);
+               unsigned int force_freq, int persistent_group,
+               const u8 *force_ssid, size_t force_ssid_len,
+               int pd_before_go_neg, unsigned int pref_freq);
 
 /**
  * p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -873,6 +949,11 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
  * @persistent_group: Whether to create a persistent group (0 = no, 1 =
  * persistent group without persistent reconnect, 2 = persistent group with
  * persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *     a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *     force_freq == 0)
  * Returns: 0 on success, -1 on failure
  *
  * This is like p2p_connect(), but the actual group negotiation is not
@@ -881,7 +962,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 int p2p_authorize(struct p2p_data *p2p, 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);
+                 unsigned int force_freq, int persistent_group,
+                 const u8 *force_ssid, size_t force_ssid_len,
+                 unsigned int pref_freq);
 
 /**
  * p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -891,6 +974,10 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
  */
 int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
 
+#ifdef TIZEN_EXT_P2P
+int p2p_reject_connection(struct p2p_data *p2p, const u8 *peer_addr);
+#endif
+
 /**
  * p2p_prov_disc_req - Send Provision Discovery Request
  * @p2p: P2P module context from p2p_init()
@@ -898,6 +985,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
  * @config_methods: WPS Config Methods value (only one bit set)
  * @join: Whether this is used by a client joining an active group
  * @force_freq: Forced TX frequency for the frame (mainly for the join case)
+ * @user_initiated_pd: Flag to indicate if initiated by user or not
  * Returns: 0 on success, -1 on failure
  *
  * This function can be used to request a discovered P2P peer to display a PIN
@@ -909,7 +997,8 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
  * indicated with the p2p_config::prov_disc_resp() callback.
  */
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-                     u16 config_methods, int join, int force_freq);
+                     u16 config_methods, int join, int force_freq,
+                     int user_initiated_pd);
 
 /**
  * p2p_sd_request - Schedule a service discovery query
@@ -924,6 +1013,11 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
 void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
                      const struct wpabuf *tlvs);
 
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+                         const struct wpabuf *tlvs);
+#endif /* CONFIG_WIFI_DISPLAY */
+
 /**
  * p2p_sd_cancel_request - Cancel a pending service discovery query
  * @p2p: P2P module context from p2p_init()
@@ -974,12 +1068,14 @@ enum p2p_invite_role {
  * @force_freq: The only allowed channel frequency in MHz or 0
  * @go_dev_addr: Forced GO Device Address or %NULL if none
  * @persistent_group: Whether this is to reinvoke a persistent group
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *     force_freq == 0)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
               const u8 *bssid, const u8 *ssid, size_t ssid_len,
               unsigned int force_freq, const u8 *go_dev_addr,
-              int persistent_group);
+              int persistent_group, unsigned int pref_freq);
 
 /**
  * p2p_presence_req - Request GO presence
@@ -1054,17 +1150,34 @@ u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
 /**
  * p2p_clear_provisioning_info - Clear any stored provisioning info
  * @p2p: P2P module context from p2p_init()
- * @iface_addr: Peer P2P Interface Address
+ * @iface_addr: Peer P2P Device Address
  *
  * This function is used to clear stored WPS provisioning info for the given
  * peer.
  */
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
 
 
 /* Event notifications from lower layer driver operations */
 
 /**
+ * enum p2p_probe_req_status
+ *
+ * @P2P_PREQ_MALFORMED: frame was not well-formed
+ * @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored
+ * @P2P_PREQ_NOT_P2P: frame was not a P2P probe request
+ * @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed
+ * @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P
+ */
+enum p2p_probe_req_status {
+       P2P_PREQ_MALFORMED,
+       P2P_PREQ_NOT_LISTEN,
+       P2P_PREQ_NOT_P2P,
+       P2P_PREQ_NOT_PROCESSED,
+       P2P_PREQ_PROCESSED
+};
+
+/**
  * p2p_probe_req_rx - Report reception of a Probe Request frame
  * @p2p: P2P module context from p2p_init()
  * @addr: Source MAC address
@@ -1072,10 +1185,11 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
  * @bssid: BSSID if available or %NULL
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
- * Returns: 0 to indicate the frame was not processed or 1 if it was
+ * Returns: value indicating the type and status of the probe request
  */
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-                    const u8 *bssid, const u8 *ie, size_t ie_len);
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+                const u8 *bssid, const u8 *ie, size_t ie_len);
 
 /**
  * p2p_rx_action - Report received Action frame
@@ -1097,6 +1211,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
  * @p2p: P2P module context from p2p_init()
  * @bssid: BSSID of the scan result
  * @freq: Frequency of the channel on which the device was found in MHz
+ * @rx_time: Time when the result was received
  * @level: Signal level (signal strength of the received Beacon/Probe Response
  *     frame)
  * @ies: Pointer to IEs from the scan result
@@ -1118,7 +1233,8 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
  * start of a pending operation, e.g., to start a pending GO negotiation.
  */
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-                        int level, const u8 *ies, size_t ies_len);
+                        struct os_time *rx_time, int level, const u8 *ies,
+                        size_t ies_len);
 
 /**
  * p2p_scan_res_handled - Indicate end of scan results
@@ -1214,6 +1330,16 @@ struct p2p_group_config {
        unsigned int max_clients;
 
        /**
+        * ssid - Group SSID
+        */
+       u8 ssid[32];
+
+       /**
+        * ssid_len - Length of SSID
+        */
+       size_t ssid_len;
+
+       /**
         * cb_ctx - Context to use with callback functions
         */
        void *cb_ctx;
@@ -1324,6 +1450,11 @@ int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
 int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps);
 
 /**
+ * p2p_group_match_dev_id - Match P2P Device Address in group with requested device id
+ */
+int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p);
+
+/**
  * p2p_group_go_discover - Send GO Discoverability Request to a group client
  * @group: P2P group context from p2p_group_init()
  * Returns: 0 on success (frame scheduled); -1 if client was not found
@@ -1360,6 +1491,24 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end);
 int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end);
 
 /**
+ * p2p_parse_dev_addr_in_p2p_ie - Parse P2P Device Address from a concatenated
+ * P2P IE
+ * @p2p_ie: P2P IE
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr);
+
+/**
+ * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s)
+ * @ies: Information elements from scan results
+ * @ies_len: ies buffer length in octets
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr);
+
+/**
  * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame
  * @p2p: P2P module context from p2p_init()
  * @bssid: BSSID
@@ -1376,8 +1525,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
  * p2p_scan_ie - Build P2P IE for Probe Request
  * @p2p: P2P module context from p2p_init()
  * @ies: Buffer for writing P2P IE
+ * @dev_id: Device ID to search for or %NULL for any
  */
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id);
 
 /**
  * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
@@ -1416,16 +1566,36 @@ int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie);
 const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
 
 /**
- * p2p_get_peer_info - Get P2P peer information in text format
+ * p2p_get_peer_info - Get P2P peer information
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
  * @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+                                              const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
  * @buf: Buffer for returning text
  * @buflen: Maximum buffer length
  * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
+ */
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+                         char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
  */
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-                     char *buf, size_t buflen);
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
 
 /**
  * p2p_set_client_discoverability - Set client discoverability capability
@@ -1439,7 +1609,7 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
 
 /**
- * p2p_set_manageD_oper - Set managed P2P Device operations capability
+ * p2p_set_managed_oper - Set managed P2P Device operations capability
  * @p2p: P2P module context from p2p_init()
  * @enabled: Whether managed P2P Device operations will be enabled
  */
@@ -1465,9 +1635,6 @@ void p2p_set_cross_connect(struct p2p_data *p2p, int enabled);
 
 int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr);
 
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-                  const u8 *ies, size_t ies_len);
-
 /**
  * p2p_set_intra_bss_dist - Set intra BSS distribution
  * @p2p: P2P module context from p2p_init()
@@ -1475,6 +1642,9 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
  */
 void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
 
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+                              unsigned int freq);
+
 /**
  * p2p_supported_freq - Check whether channel is supported for P2P
  * @p2p: P2P module context from p2p_init()
@@ -1483,6 +1653,15 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
  */
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 
+/**
+ * p2p_get_pref_freq - Get channel from preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @channels: List of channels
+ * Returns: Preferred channel
+ */
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+                              const struct p2p_channels *channels);
+
 void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
 
 /**
@@ -1495,6 +1674,17 @@ void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
 void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
                           int freq_overall);
 
+/**
+ * p2p_set_own_freq_preference - Set own preference for channel
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency (MHz) of the preferred channel or 0 if no preference
+ *
+ * This function can be used to set a preference on the operating channel based
+ * on frequencies used on the other virtual interfaces that share the same
+ * radio. If non-zero, this is used to try to avoid multi-channel concurrency.
+ */
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq);
+
 const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
 
 /**
@@ -1523,6 +1713,14 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
 const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
 
 /**
+ * p2p_group_is_client_connected - Check whether a specific client is connected
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Device Address of the client
+ * Returns: 1 if client is connected or 0 if not
+ */
+int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
+
+/**
  * p2p_get_peer_found - Get P2P peer info structure of a found peer
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1562,6 +1760,16 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
                         int cfg_op_channel);
 
 /**
+ * p2p_set_pref_chan - Set P2P preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @num_pref_chan: Number of entries in pref_chan list
+ * @pref_chan: Preferred channels or %NULL to remove preferences
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+                     const struct p2p_channel *pref_chan);
+
+/**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
  * Returns: 0 if P2P module is idle or 1 if an operation is in progress
@@ -1577,4 +1785,50 @@ int p2p_other_scan_completed(struct p2p_data *p2p);
 
 const char * p2p_wps_method_text(enum p2p_wps_method method);
 
+/**
+ * p2p_set_config_timeout - Set local config timeouts
+ * @p2p: P2P module context from p2p_init()
+ * @go_timeout: Time in 10 ms units it takes to start the GO mode
+ * @client_timeout: Time in 10 ms units it takes to start the client mode
+ */
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+                           u8 client_timeout);
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+                                 const struct wpabuf *elem);
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
+
+/**
+ * p2p_set_disc_int - Set min/max discoverable interval for p2p_find
+ * @p2p: P2P module context from p2p_init()
+ * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1
+ * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3
+ * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or
+ *     -1 not to limit
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function can be used to configure minDiscoverableInterval and
+ * maxDiscoverableInterval parameters for the Listen state during device
+ * discovery (p2p_find). A random number of 100 TU units is picked for each
+ * Listen state iteration from [min_disc_int,max_disc_int] range.
+ *
+ * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * it should be noted that use of this parameter is not recommended since it
+ * would not be compliant with the P2P specification.
+ */
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+                    int max_disc_tu);
+
 #endif /* P2P_H */
index a82e16d..5838d35 100644 (file)
@@ -2,14 +2,8 @@
  * P2P - IE builder
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -138,7 +132,8 @@ void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
 
        /* Update attribute length */
        WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
-       wpa_printf(MSG_DEBUG, "P2P: * Channel List");
+       wpa_hexdump(MSG_DEBUG, "P2P: * Channel List",
+                   len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
 }
 
 
@@ -357,7 +352,7 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
 }
 
 
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
                      int all_attr)
 {
        u8 *len;
@@ -375,11 +370,14 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
                wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
        }
 
-       /* Device Password ID */
-       wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
-       wpabuf_put_be16(buf, 2);
-       wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", pw_id);
-       wpabuf_put_be16(buf, pw_id);
+       if (pw_id >= 0) {
+               /* Device Password ID */
+               wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
+               wpabuf_put_be16(buf, 2);
+               wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
+                          pw_id);
+               wpabuf_put_be16(buf, pw_id);
+       }
 
        if (all_attr) {
                wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
index 47cc0fd..76d01cf 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P Device Discoverability procedure
  * Copyright (c) 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -48,8 +42,7 @@ static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
 
 void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Device Discoverability Request TX callback: success=%d",
+       p2p_dbg(p2p, "Device Discoverability Request TX callback: success=%d",
                success);
 
        if (!success) {
@@ -62,9 +55,7 @@ void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
                return;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO acknowledged Device Discoverability Request - wait "
-               "for response");
+       p2p_dbg(p2p, "GO acknowledged Device Discoverability Request - wait for response");
        /*
         * TODO: is the remain-on-channel from Action frame TX long enough for
         * most cases or should we try to increase its duration and/or start
@@ -80,9 +71,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
 
        go = p2p_get_device(p2p, dev->member_in_go_dev);
        if (go == NULL || dev->oper_freq <= 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Could not find peer entry for GO and frequency "
-                       "to send Device Discoverability Request");
+               p2p_dbg(p2p, "Could not find peer entry for GO and frequency to send Device Discoverability Request");
                return -1;
        }
 
@@ -90,8 +79,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
        if (req == NULL)
                return -1;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending Device Discoverability Request to GO " MACSTR
+       p2p_dbg(p2p, "Sending Device Discoverability Request to GO " MACSTR
                " for client " MACSTR,
                MAC2STR(go->info.p2p_device_addr),
                MAC2STR(dev->info.p2p_device_addr));
@@ -103,8 +91,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
        if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
                            p2p->cfg->dev_addr, go->info.p2p_device_addr,
                            wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
                wpabuf_free(req);
                /* TODO: how to recover from failure? */
                return -1;
@@ -137,8 +124,7 @@ static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
 
 void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Device Discoverability Response TX callback: success=%d",
+       p2p_dbg(p2p, "Device Discoverability Response TX callback: success=%d",
                success);
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 }
@@ -153,8 +139,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
        if (resp == NULL)
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending Device Discoverability Response to " MACSTR
+       p2p_dbg(p2p, "Sending Device Discoverability Response to " MACSTR
                " (status %u freq %d)",
                MAC2STR(addr), status, freq);
 
@@ -162,8 +147,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
        if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
                            p2p->cfg->dev_addr,
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
 
        wpabuf_free(resp);
@@ -176,17 +160,14 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
        struct p2p_message msg;
        size_t g;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Device Discoverability Request from " MACSTR
+       p2p_dbg(p2p, "Received Device Discoverability Request from " MACSTR
                " (freq=%d)", MAC2STR(sa), rx_freq);
 
        if (p2p_parse(data, len, &msg))
                return;
 
        if (msg.dialog_token == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid Dialog Token 0 (must be nonzero) in "
-                       "Device Discoverability Request");
+               p2p_dbg(p2p, "Invalid Dialog Token 0 (must be nonzero) in Device Discoverability Request");
                p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
                                       P2P_SC_FAIL_INVALID_PARAMS);
                p2p_parse_free(&msg);
@@ -194,9 +175,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (msg.device_id == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: P2P Device ID attribute missing from Device "
-                       "Discoverability Request");
+               p2p_dbg(p2p, "P2P Device ID attribute missing from Device Discoverability Request");
                p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
                                       P2P_SC_FAIL_INVALID_PARAMS);
                p2p_parse_free(&msg);
@@ -206,9 +185,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
        for (g = 0; g < p2p->num_groups; g++) {
                if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
                                          rx_freq) == 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
-                               "GO Discoverability Request for the target "
-                               "device");
+                       p2p_dbg(p2p, "Scheduled GO Discoverability Request for the target device");
                        /*
                         * P2P group code will use a callback to indicate TX
                         * status, so that we can reply to the request once the
@@ -223,9 +200,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
                }
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
-               "was not found in any group or did not support client "
-               "discoverability");
+       p2p_dbg(p2p, "Requested client was not found in any group or did not support client discoverability");
        p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
                               P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
        p2p_parse_free(&msg);
@@ -239,15 +214,13 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
        struct p2p_device *go;
        u8 status;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Device Discoverability Response from " MACSTR,
+       p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR,
                MAC2STR(sa));
 
        go = p2p->pending_client_disc_go;
        if (go == NULL ||
            os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
-                       "Device Discoverability Response");
+               p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response");
                return;
        }
 
@@ -260,9 +233,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (msg.dialog_token != go->dialog_token) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
-                       "Discoverability Response with unexpected dialog "
-                       "token %u (expected %u)",
+               p2p_dbg(p2p, "Ignore Device Discoverability Response with unexpected dialog token %u (expected %u)",
                        msg.dialog_token, go->dialog_token);
                p2p_parse_free(&msg);
                return;
@@ -271,17 +242,14 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
        status = *msg.status;
        p2p_parse_free(&msg);
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Device Discoverability Response status %u", status);
+       p2p_dbg(p2p, "Device Discoverability Response status %u", status);
 
        if (p2p->go_neg_peer == NULL ||
            os_memcmp(p2p->pending_client_disc_addr,
                      p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
            os_memcmp(p2p->go_neg_peer->member_in_go_dev,
                      go->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
-                       "operation with the client discoverability peer "
-                       "anymore");
+               p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore");
                return;
        }
 
@@ -290,8 +258,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
                 * Peer is expected to be awake for at least 100 TU; try to
                 * connect immediately.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Client discoverability request succeeded");
+               p2p_dbg(p2p, "Client discoverability request succeeded");
                if (p2p->state == P2P_CONNECT) {
                        /*
                         * Change state to force the timeout to start in
@@ -307,8 +274,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
                 * Client discoverability request failed; try to connect from
                 * timeout.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Client discoverability request failed");
+               p2p_dbg(p2p, "Client discoverability request failed");
                p2p_set_timeout(p2p, 0, 500000);
        }
 
@@ -317,14 +283,12 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
 
 void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Discoverability Request TX callback: success=%d",
+       p2p_dbg(p2p, "GO Discoverability Request TX callback: success=%d",
                success);
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
        if (p2p->pending_dev_disc_dialog_token == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
-                       "Discoverability Request");
+               p2p_dbg(p2p, "No pending Device Discoverability Request");
                return;
        }
 
@@ -344,9 +308,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
        unsigned int tu;
        struct wpabuf *ies;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GO Discoverability Request - remain awake for "
-               "100 TU");
+       p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
 
        ies = p2p_build_probe_resp_ies(p2p);
        if (ies == NULL)
@@ -357,9 +319,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
        tu = 100;
        if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
                    ies) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to start listen mode for client "
-                       "discoverability");
+               p2p_dbg(p2p, "Failed to start listen mode for client discoverability");
        }
        wpabuf_free(ies);
 }
index eb85f51..53914b1 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P Group Owner Negotiation
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -55,8 +49,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
        os_memcpy(dev->country, pos, 3);
        wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3);
        if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-                       "P2P: Mismatching country (ours=%c%c peer's=%c%c)",
+               p2p_info(p2p, "Mismatching country (ours=%c%c peer's=%c%c)",
                        p2p->cfg->country[0], p2p->cfg->country[1],
                        pos[0], pos[1]);
                return -1;
@@ -67,8 +60,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
                struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
                cl->reg_class = *pos++;
                if (pos + 1 + pos[0] > end) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-                               "P2P: Invalid peer Channel List");
+                       p2p_info(p2p, "Invalid peer Channel List");
                        return -1;
                }
                channels = *pos++;
@@ -82,14 +74,12 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
        }
 
        p2p_channels_intersect(own, &dev->channels, &intersection);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own reg_classes %d "
-               "peer reg_classes %d intersection reg_classes %d",
+       p2p_dbg(p2p, "Own reg_classes %d peer reg_classes %d intersection reg_classes %d",
                (int) own->reg_classes,
                (int) dev->channels.reg_classes,
                (int) intersection.reg_classes);
        if (intersection.reg_classes == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-                       "P2P: No common channels found");
+               p2p_info(p2p, "No common channels found");
                return -1;
        }
        return 0;
@@ -104,7 +94,7 @@ static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev,
 }
 
 
-static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
 {
        switch (wps_method) {
        case WPS_PIN_DISPLAY:
@@ -140,14 +130,17 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
        struct wpabuf *buf;
        u8 *len;
        u8 group_capab;
+       size_t extra = 0;
 
-       buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
-       peer->dialog_token++;
-       if (peer->dialog_token == 0)
-               peer->dialog_token = 1;
        p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
 
        len = p2p_buf_add_ie_hdr(buf);
@@ -161,11 +154,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
                group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
        if (p2p->cfg->p2p_intra_bss)
                group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
-       p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
-                             p2p->next_tie_breaker);
-       p2p->next_tie_breaker = !p2p->next_tie_breaker;
-       p2p_buf_add_config_timeout(buf, 100, 20);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
+       p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
+       p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
        p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
                                   p2p->cfg->channel);
        if (p2p->ext_listen_interval)
@@ -181,6 +174,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
        /* WPS IE with Device Password ID attribute */
        p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -190,11 +188,26 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
        struct wpabuf *req;
        int freq;
 
+       if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+               u16 config_method;
+               p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR,
+                       MAC2STR(dev->info.p2p_device_addr));
+               if (dev->wps_method == WPS_PIN_DISPLAY)
+                       config_method = WPS_CONFIG_KEYPAD;
+               else if (dev->wps_method == WPS_PIN_KEYPAD)
+                       config_method = WPS_CONFIG_DISPLAY;
+               else if (dev->wps_method == WPS_PBC)
+                       config_method = WPS_CONFIG_PUSHBUTTON;
+               else
+                       return -1;
+               return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
+                                        config_method, 0, 0, 1);
+       }
+
        freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
        if (freq <= 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Listen/Operating frequency known for the "
-                       "peer " MACSTR " to send GO Negotiation Request",
+               p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+                       MACSTR " to send GO Negotiation Request",
                        MAC2STR(dev->info.p2p_device_addr));
                return -1;
        }
@@ -202,18 +215,61 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
        req = p2p_build_go_neg_req(p2p, dev);
        if (req == NULL)
                return -1;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending GO Negotiation Request");
+       p2p_dbg(p2p, "Sending GO Negotiation Request");
        p2p_set_state(p2p, P2P_CONNECT);
        p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
        p2p->go_neg_peer = dev;
        dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
        dev->connect_reqs++;
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, dev->info.p2p_device_addr,
+#else
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
+#endif
+                           wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+               p2p_dbg(p2p, "Failed to send Action frame");
+               /* Use P2P find to recover and retry */
+               p2p_set_timeout(p2p, 0, 0);
+       } else
+               dev->go_neg_req_sent++;
+
+       wpabuf_free(req);
+
+       return 0;
+}
+#ifdef TIZEN_EXT_P2P
+int p2p_reject_send(struct p2p_data *p2p, struct p2p_device *dev)
+{
+       struct wpabuf *req;
+       int freq;
+
+       freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+       if (freq <= 0) {
+               p2p_dbg(p2p, "P2P: No Listen/Operating frequency known for the "
+                       "peer " MACSTR " to send GO Negotiation Request",
+                       MAC2STR(dev->info.p2p_device_addr));
+               return -1;
+       }
+
+       dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
+       dev->flags |= P2P_DEV_USER_REJECTED;
+
+       req = p2p_build_go_neg_req(p2p, dev);
+       if (req == NULL)
+               return -1;
+       p2p_dbg(p2p, "P2P: Sending GO Negotiation Request(reject)");
+       p2p_set_state(p2p, P2P_CONNECT);
+       p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
+       p2p->go_neg_peer = dev;
+       dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
+       dev->connect_reqs++;
+       wpa_printf(MSG_DEBUG, "[KGB_DEBUG] %s(): Sending GO Neg request. Dst [" MACSTR "], Src [" MACSTR "], BSSID [" MACSTR "]",
+                               __func__, MAC2STR(dev->info.p2p_device_addr), MAC2STR(p2p->cfg->own_addr), MAC2STR(dev->info.p2p_device_addr));
+       if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+                           p2p->cfg->own_addr, dev->info.p2p_device_addr,
                            wpabuf_head(req), wpabuf_len(req), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "P2P: Failed to send Action frame");
                /* Use P2P find to recover and retry */
                p2p_set_timeout(p2p, 0, 0);
        }
@@ -222,6 +278,7 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
 
        return 0;
 }
+#endif
 
 
 static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
@@ -232,10 +289,16 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
        struct wpabuf *buf;
        u8 *len;
        u8 group_capab;
+       size_t extra = 0;
+
+       p2p_dbg(p2p, "Building GO Negotiation Response");
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Building GO Negotiation Response");
-       buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -256,12 +319,13 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
                if (p2p->cfg->p2p_intra_bss)
                        group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
        }
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
        p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
-       p2p_buf_add_config_timeout(buf, 100, 20);
+       p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
        if (peer && peer->go_state == REMOTE_GO) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
-                       "Channel attribute");
+               p2p_dbg(p2p, "Omit Operating Channel attribute");
        } else {
                p2p_buf_add_operating_channel(buf, p2p->cfg->country,
                                              p2p->op_reg_class,
@@ -282,8 +346,13 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
        }
        p2p_buf_add_device_info(buf, p2p, peer);
        if (peer && peer->go_state == LOCAL_GO) {
+#ifdef TIZEN_EXT_P2P
+               p2p_buf_add_group_id(buf, p2p->cfg->own_addr, p2p->ssid,
+                                    p2p->ssid_len);
+#else
                p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
                                     p2p->ssid_len);
+#endif
        }
        p2p_buf_update_ie_hdr(buf, len);
 
@@ -292,30 +361,66 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
                         p2p_wps_method_pw_id(peer ? peer->wps_method :
                                              WPS_NOT_READY), 0);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
        return buf;
 }
 
 
-static void p2p_reselect_channel(struct p2p_data *p2p,
-                                struct p2p_channels *intersection)
+/**
+ * p2p_reselect_channel - Re-select operating channel based on peer information
+ * @p2p: P2P module context from p2p_init()
+ * @intersection: Support channel list intersection from local and peer
+ *
+ * This function is used to re-select the best channel after having received
+ * information from the peer to allow supported channel lists to be intersected.
+ * This can be used to improve initial channel selection done in
+ * p2p_prepare_channel() prior to the start of GO Negotiation. In addition, this
+ * can be used for Invitation case.
+ */
+void p2p_reselect_channel(struct p2p_data *p2p,
+                         struct p2p_channels *intersection)
 {
        struct p2p_reg_class *cl;
        int freq;
        u8 op_reg_class, op_channel;
+       unsigned int i;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
-               "channel (reg_class %u channel %u) not acceptable to the "
-               "peer", p2p->op_reg_class, p2p->op_channel);
+       if (p2p->own_freq_preference > 0 &&
+           p2p_freq_to_channel(p2p->own_freq_preference,
+                               &op_reg_class, &op_channel) == 0 &&
+           p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+               p2p_dbg(p2p, "Pick own channel preference (reg_class %u channel %u) from intersection",
+                       op_reg_class, op_channel);
+               p2p->op_reg_class = op_reg_class;
+               p2p->op_channel = op_channel;
+               return;
+       }
+
+       if (p2p->best_freq_overall > 0 &&
+           p2p_freq_to_channel(p2p->best_freq_overall,
+                               &op_reg_class, &op_channel) == 0 &&
+           p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+               p2p_dbg(p2p, "Pick best overall channel (reg_class %u channel %u) from intersection",
+                       op_reg_class, op_channel);
+               p2p->op_reg_class = op_reg_class;
+               p2p->op_channel = op_channel;
+               return;
+       }
 
        /* First, try to pick the best channel from another band */
-       freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
-                                  p2p->op_channel);
+       freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
        if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
-           p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+           !p2p_channels_includes(intersection, p2p->op_reg_class,
+                                  p2p->op_channel) &&
+           p2p_freq_to_channel(p2p->best_freq_5,
                                &op_reg_class, &op_channel) == 0 &&
            p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
-                       "channel (reg_class %u channel %u) from intersection",
+               p2p_dbg(p2p, "Pick best 5 GHz channel (reg_class %u channel %u) from intersection",
                        op_reg_class, op_channel);
                p2p->op_reg_class = op_reg_class;
                p2p->op_channel = op_channel;
@@ -323,30 +428,117 @@ static void p2p_reselect_channel(struct p2p_data *p2p,
        }
 
        if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
-           p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+           !p2p_channels_includes(intersection, p2p->op_reg_class,
+                                  p2p->op_channel) &&
+           p2p_freq_to_channel(p2p->best_freq_24,
                                &op_reg_class, &op_channel) == 0 &&
            p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
-                       "channel (reg_class %u channel %u) from intersection",
+               p2p_dbg(p2p, "Pick best 2.4 GHz channel (reg_class %u channel %u) from intersection",
                        op_reg_class, op_channel);
                p2p->op_reg_class = op_reg_class;
                p2p->op_channel = op_channel;
                return;
        }
 
+       /* Select channel with highest preference if the peer supports it */
+       for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+               if (p2p_channels_includes(intersection,
+                                         p2p->cfg->pref_chan[i].op_class,
+                                         p2p->cfg->pref_chan[i].chan)) {
+                       p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
+                       p2p->op_channel = p2p->cfg->pref_chan[i].chan;
+                       p2p_dbg(p2p, "Pick highest preferred channel (op_class %u channel %u) from intersection",
+                               p2p->op_reg_class, p2p->op_channel);
+                       return;
+               }
+       }
+
+       /* Try a channel where we might be able to use HT40 */
+       for (i = 0; i < intersection->reg_classes; i++) {
+               struct p2p_reg_class *c = &intersection->reg_class[i];
+               if (c->reg_class == 116 || c->reg_class == 117 ||
+                   c->reg_class == 126 || c->reg_class == 127) {
+                       p2p_dbg(p2p, "Pick possible HT40 channel (reg_class %u channel %u) from intersection",
+                               c->reg_class, c->channel[0]);
+                       p2p->op_reg_class = c->reg_class;
+                       p2p->op_channel = c->channel[0];
+                       return;
+               }
+       }
+
+       /*
+        * Try to see if the original channel is in the intersection. If
+        * so, no need to change anything, as it already contains some
+        * randomness.
+        */
+       if (p2p_channels_includes(intersection, p2p->op_reg_class,
+                                 p2p->op_channel)) {
+               p2p_dbg(p2p, "Using original operating class and channel (op_class %u channel %u) from intersection",
+                       p2p->op_reg_class, p2p->op_channel);
+               return;
+       }
+
        /*
         * Fall back to whatever is included in the channel intersection since
         * no better options seems to be available.
         */
        cl = &intersection->reg_class[0];
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick another channel "
-               "(reg_class %u channel %u) from intersection",
+       p2p_dbg(p2p, "Pick another channel (reg_class %u channel %u) from intersection",
                cl->reg_class, cl->channel[0]);
        p2p->op_reg_class = cl->reg_class;
        p2p->op_channel = cl->channel[0];
 }
 
 
+static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+                                u8 *status)
+{
+       struct p2p_channels intersection;
+       size_t i;
+
+       p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+       if (intersection.reg_classes == 0 ||
+           intersection.reg_class[0].channels == 0) {
+               *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+               p2p_dbg(p2p, "No common channels found");
+               return -1;
+       }
+
+       for (i = 0; i < intersection.reg_classes; i++) {
+               struct p2p_reg_class *c;
+               c = &intersection.reg_class[i];
+               p2p_dbg(p2p, "reg_class %u", c->reg_class);
+               wpa_hexdump(MSG_DEBUG, "P2P: channels",
+                           c->channel, c->channels);
+       }
+
+       if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+                                  p2p->op_channel)) {
+               if (dev->flags & P2P_DEV_FORCE_FREQ) {
+                       *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+                       p2p_dbg(p2p, "Peer does not support the forced channel");
+                       return -1;
+               }
+
+               p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer",
+                       p2p->op_reg_class, p2p->op_channel);
+               p2p_reselect_channel(p2p, &intersection);
+       } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+                  !p2p->cfg->cfg_op_channel) {
+               p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u",
+                       p2p->op_reg_class, p2p->op_channel);
+               p2p_reselect_channel(p2p, &intersection);
+       }
+
+       if (!p2p->ssid_set) {
+               p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+               p2p->ssid_set = 1;
+       }
+
+       return 0;
+}
+
+
 void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
                            const u8 *data, size_t len, int rx_freq)
 {
@@ -357,17 +549,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        int tie_breaker = 0;
        int freq;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GO Negotiation Request from " MACSTR
-               "(freq=%d)", MAC2STR(sa), rx_freq);
+       p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
+               MAC2STR(sa), rx_freq);
 
        if (p2p_parse(data, len, &msg))
                return;
 
        if (!msg.capability) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Capability attribute missing from GO "
-                       "Negotiation Request");
+               p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
                goto fail;
 #endif /* CONFIG_P2P_STRICT */
@@ -376,53 +565,42 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        if (msg.go_intent)
                tie_breaker = *msg.go_intent & 0x01;
        else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory GO Intent attribute missing from GO "
-                       "Negotiation Request");
+               p2p_dbg(p2p, "Mandatory GO Intent attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
                goto fail;
 #endif /* CONFIG_P2P_STRICT */
        }
 
        if (!msg.config_timeout) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Configuration Timeout attribute "
-                       "missing from GO Negotiation Request");
+               p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
                goto fail;
 #endif /* CONFIG_P2P_STRICT */
        }
 
        if (!msg.listen_channel) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Listen Channel attribute received");
+               p2p_dbg(p2p, "No Listen Channel attribute received");
                goto fail;
        }
        if (!msg.operating_channel) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Operating Channel attribute received");
+               p2p_dbg(p2p, "No Operating Channel attribute received");
                goto fail;
        }
        if (!msg.channel_list) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Channel List attribute received");
+               p2p_dbg(p2p, "No Channel List attribute received");
                goto fail;
        }
        if (!msg.intended_addr) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Intended P2P Interface Address attribute "
-                       "received");
+               p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
                goto fail;
        }
        if (!msg.p2p_device_info) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No P2P Device Info attribute received");
+               p2p_dbg(p2p, "No P2P Device Info attribute received");
                goto fail;
        }
 
        if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected GO Negotiation Request SA=" MACSTR
+               p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR
                        " != dev_addr=" MACSTR,
                        MAC2STR(sa), MAC2STR(msg.p2p_device_addr));
                goto fail;
@@ -431,9 +609,8 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        dev = p2p_get_device(p2p, sa);
 
        if (msg.status && *msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected Status attribute (%d) in GO "
-                       "Negotiation Request", *msg.status);
+               p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
+                       *msg.status);
                goto fail;
        }
 
@@ -442,173 +619,116 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
        else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
                p2p_add_dev_info(p2p, sa, dev, &msg);
        if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: User has rejected this peer");
+               p2p_dbg(p2p, "User has rejected this peer");
                status = P2P_SC_FAIL_REJECTED_BY_USER;
        } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Not ready for GO negotiation with " MACSTR,
+               p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
                        MAC2STR(sa));
                status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
-               if (dev)
-                       dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
                p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa,
                                        msg.dev_password_id);
        } else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Already in Group Formation with another peer");
+               p2p_dbg(p2p, "Already in Group Formation with another peer");
                status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
        } else {
                int go;
 
                if (!p2p->go_neg_peer) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting "
-                               "GO Negotiation with previously authorized "
-                               "peer");
+                       p2p_dbg(p2p, "Starting GO Negotiation with previously authorized peer");
                        if (!(dev->flags & P2P_DEV_FORCE_FREQ)) {
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: Use default channel settings");
+                               p2p_dbg(p2p, "Use default channel settings");
                                p2p->op_reg_class = p2p->cfg->op_reg_class;
                                p2p->op_channel = p2p->cfg->op_channel;
                                os_memcpy(&p2p->channels, &p2p->cfg->channels,
                                          sizeof(struct p2p_channels));
                        } else {
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: Use previously configured "
-                                       "forced channel settings");
+                               p2p_dbg(p2p, "Use previously configured forced channel settings");
                        }
                }
 
                dev->flags &= ~P2P_DEV_NOT_YET_READY;
 
                if (!msg.go_intent) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: No GO Intent attribute received");
+                       p2p_dbg(p2p, "No GO Intent attribute received");
                        goto fail;
                }
                if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Invalid GO Intent value (%u) received",
+                       p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
                                *msg.go_intent >> 1);
                        goto fail;
                }
 
                if (dev->go_neg_req_sent &&
                    os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Do not reply since peer has higher "
-                               "address and GO Neg Request already sent");
+                       p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
                        p2p_parse_free(&msg);
                        return;
                }
 
                go = p2p_go_det(p2p->go_intent, *msg.go_intent);
                if (go < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Incompatible GO Intent");
+                       p2p_dbg(p2p, "Incompatible GO Intent");
                        status = P2P_SC_FAIL_BOTH_GO_INTENT_15;
                        goto fail;
                }
 
                if (p2p_peer_channels(p2p, dev, msg.channel_list,
                                      msg.channel_list_len) < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: No common channels found");
+                       p2p_dbg(p2p, "No common channels found");
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
                }
 
                switch (msg.dev_password_id) {
                case DEV_PW_REGISTRAR_SPECIFIED:
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: PIN from peer Display");
+                       p2p_dbg(p2p, "PIN from peer Display");
                        if (dev->wps_method != WPS_PIN_KEYPAD) {
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: We have wps_method=%s -> "
-                                       "incompatible",
+                               p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                        p2p_wps_method_str(dev->wps_method));
                                status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                                goto fail;
                        }
                        break;
                case DEV_PW_USER_SPECIFIED:
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Peer entered PIN on Keypad");
+                       p2p_dbg(p2p, "Peer entered PIN on Keypad");
                        if (dev->wps_method != WPS_PIN_DISPLAY) {
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: We have wps_method=%s -> "
-                                       "incompatible",
+                               p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                        p2p_wps_method_str(dev->wps_method));
                                status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                                goto fail;
                        }
                        break;
                case DEV_PW_PUSHBUTTON:
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Peer using pushbutton");
+                       p2p_dbg(p2p, "Peer using pushbutton");
                        if (dev->wps_method != WPS_PBC) {
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: We have wps_method=%s -> "
-                                       "incompatible",
+                               p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                        p2p_wps_method_str(dev->wps_method));
                                status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                                goto fail;
                        }
                        break;
                default:
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unsupported Device Password ID %d",
+                       p2p_dbg(p2p, "Unsupported Device Password ID %d",
                                msg.dev_password_id);
                        status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                        goto fail;
                }
 
-               if (go) {
-                       struct p2p_channels intersection;
-                       size_t i;
-                       p2p_channels_intersect(&p2p->channels, &dev->channels,
-                                              &intersection);
-                       if (intersection.reg_classes == 0 ||
-                           intersection.reg_class[0].channels == 0) {
-                               status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-                               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                                       "P2P: No common channels found");
-                               goto fail;
-                       }
-                       for (i = 0; i < intersection.reg_classes; i++) {
-                               struct p2p_reg_class *c;
-                               c = &intersection.reg_class[i];
-                               wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
-                                          c->reg_class);
-                               wpa_hexdump(MSG_DEBUG, "P2P: channels",
-                                           c->channel, c->channels);
-                       }
-                       if (!p2p_channels_includes(&intersection,
-                                                  p2p->op_reg_class,
-                                                  p2p->op_channel))
-                               p2p_reselect_channel(p2p, &intersection);
-
-                       if (!p2p->ssid_set) {
-                               p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
-                               p2p->ssid_set = 1;
-                       }
-               }
+               if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+                       goto fail;
 
                dev->go_state = go ? LOCAL_GO : REMOTE_GO;
-               dev->oper_freq = p2p_channel_to_freq((const char *)
-                                                    msg.operating_channel,
-                                                    msg.operating_channel[3],
+               dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
                                                     msg.operating_channel[4]);
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
-                       "channel preference: %d MHz", dev->oper_freq);
+               p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+                       dev->oper_freq);
 
                if (msg.config_timeout) {
                        dev->go_timeout = msg.config_timeout[0];
                        dev->client_timeout = msg.config_timeout[1];
                }
 
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
                if (p2p->state != P2P_IDLE)
                        p2p_stop_find_for_freq(p2p, rx_freq);
                p2p_set_state(p2p, P2P_GO_NEG);
@@ -627,31 +747,42 @@ fail:
        p2p_parse_free(&msg);
        if (resp == NULL)
                return;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending GO Negotiation Response");
+       p2p_dbg(p2p, "Sending GO Negotiation Response");
        if (rx_freq > 0)
                freq = rx_freq;
        else
-               freq = p2p_channel_to_freq(p2p->cfg->country,
-                                          p2p->cfg->reg_class,
+               freq = p2p_channel_to_freq(p2p->cfg->reg_class,
                                           p2p->cfg->channel);
        if (freq < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown regulatory class/channel");
+               p2p_dbg(p2p, "Unknown regulatory class/channel");
                wpabuf_free(resp);
                return;
        }
        if (status == P2P_SC_SUCCESS) {
                p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE;
                dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM;
+               if (os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) < 0) {
+                       /*
+                        * Peer has smaller address, so the GO Negotiation
+                        * Response from us is expected to complete
+                        * negotiation. Ignore a GO Negotiation Response from
+                        * the peer if it happens to be received after this
+                        * point due to a race condition in GO Negotiation
+                        * Request transmission and processing.
+                        */
+                       dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
+               }
        } else
                p2p->pending_action_state =
                        P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
-       if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
-                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+       if (p2p_send_action(p2p, freq, sa,
+#ifdef TIZEN_EXT_P2P
+                           p2p->cfg->own_addr, p2p->cfg->own_addr,
+#else
+                           p2p->cfg->dev_addr, p2p->cfg->dev_addr,
+#endif
+                           wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
 
        wpabuf_free(resp);
@@ -667,10 +798,16 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
        u8 *len;
        struct p2p_channels res;
        u8 group_capab;
+       size_t extra = 0;
+
+       p2p_dbg(p2p, "Building GO Negotiation Confirm");
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Building GO Negotiation Confirm");
-       buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -691,7 +828,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
                if (p2p->cfg->p2p_intra_bss)
                        group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
        }
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
        if (go || resp_chan == NULL)
                p2p_buf_add_operating_channel(buf, p2p->cfg->country,
                                              p2p->op_reg_class,
@@ -702,11 +841,21 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
        p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
        p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
        if (go) {
+#ifdef TIZEN_EXT_P2P
+               p2p_buf_add_group_id(buf, p2p->cfg->own_addr, p2p->ssid,
+                                    p2p->ssid_len);
+#else
                p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
                                     p2p->ssid_len);
+#endif
        }
        p2p_buf_update_ie_hdr(buf, len);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_go_neg)
+               wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -721,14 +870,12 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
        u8 status = P2P_SC_SUCCESS;
        int freq;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GO Negotiation Response from " MACSTR
+       p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
                " (freq=%d)", MAC2STR(sa), rx_freq);
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
            dev != p2p->go_neg_peer) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Not ready for GO negotiation with " MACSTR,
+               p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
                        MAC2STR(sa));
                return;
        }
@@ -737,44 +884,35 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
                return;
 
        if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Was not expecting GO Negotiation Response - "
-                       "ignore");
+               p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
                p2p_parse_free(&msg);
                return;
        }
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
 
        if (msg.dialog_token != dev->dialog_token) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected Dialog Token %u (expected %u)",
+               p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
                        msg.dialog_token, dev->dialog_token);
                p2p_parse_free(&msg);
                return;
        }
 
        if (!msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Status attribute received");
+               p2p_dbg(p2p, "No Status attribute received");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
        if (*msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: GO Negotiation rejected: status %d",
-                       *msg.status);
+               p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
                dev->go_neg_req_sent = 0;
                if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Wait for the peer to become ready for "
-                               "GO Negotiation");
+                       p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
                        dev->flags |= P2P_DEV_NOT_YET_READY;
                        dev->wait_count = 0;
                        p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
                        p2p_set_timeout(p2p, 0, 0);
                } else {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Stop GO Negotiation attempt");
+                       p2p_dbg(p2p, "Stop GO Negotiation attempt");
                        p2p_go_neg_failed(p2p, dev, *msg.status);
                }
                p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -783,9 +921,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (!msg.capability) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Capability attribute missing from GO "
-                       "Negotiation Response");
+               p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
@@ -793,9 +929,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (!msg.p2p_device_info) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory P2P Device Info attribute missing "
-                       "from GO Negotiation Response");
+               p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
@@ -803,22 +937,18 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (!msg.intended_addr) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Intended P2P Interface Address attribute "
-                       "received");
+               p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
 
        if (!msg.go_intent) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No GO Intent attribute received");
+               p2p_dbg(p2p, "No GO Intent attribute received");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
        if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid GO Intent value (%u) received",
+               p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
                        *msg.go_intent >> 1);
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
@@ -826,8 +956,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
 
        go = p2p_go_det(p2p->go_intent, *msg.go_intent);
        if (go < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Incompatible GO Intent");
+               p2p_dbg(p2p, "Incompatible GO Intent");
                status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
                goto fail;
        }
@@ -837,20 +966,14 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
                p2p->ssid_len = msg.group_id_len - ETH_ALEN;
                os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
        } else if (!go) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory P2P Group ID attribute missing from "
-                       "GO Negotiation Response");
+               p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response");
                p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
-#endif /* CONFIG_P2P_STRICT */
        }
 
        if (!msg.config_timeout) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Configuration Timeout attribute "
-                       "missing from GO Negotiation Response");
+               p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
@@ -865,116 +988,73 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
                 * Note: P2P Client may omit Operating Channel attribute to
                 * indicate it does not have a preference.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Operating Channel attribute received");
+               p2p_dbg(p2p, "No Operating Channel attribute received");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
        if (!msg.channel_list) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Channel List attribute received");
+               p2p_dbg(p2p, "No Channel List attribute received");
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
 
        if (p2p_peer_channels(p2p, dev, msg.channel_list,
                              msg.channel_list_len) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No common channels found");
+               p2p_dbg(p2p, "No common channels found");
                status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                goto fail;
        }
 
        if (msg.operating_channel) {
-               dev->oper_freq = p2p_channel_to_freq((const char *)
-                                                    msg.operating_channel,
-                                                    msg.operating_channel[3],
+               dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
                                                     msg.operating_channel[4]);
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
-                       "channel preference: %d MHz", dev->oper_freq);
+               p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+                       dev->oper_freq);
        } else
                dev->oper_freq = 0;
 
        switch (msg.dev_password_id) {
        case DEV_PW_REGISTRAR_SPECIFIED:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: PIN from peer Display");
+               p2p_dbg(p2p, "PIN from peer Display");
                if (dev->wps_method != WPS_PIN_KEYPAD) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: We have wps_method=%s -> "
-                               "incompatible",
+                       p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                p2p_wps_method_str(dev->wps_method));
                        status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                        goto fail;
                }
                break;
        case DEV_PW_USER_SPECIFIED:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Peer entered PIN on Keypad");
+               p2p_dbg(p2p, "Peer entered PIN on Keypad");
                if (dev->wps_method != WPS_PIN_DISPLAY) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: We have wps_method=%s -> "
-                               "incompatible",
+                       p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                p2p_wps_method_str(dev->wps_method));
                        status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                        goto fail;
                }
                break;
        case DEV_PW_PUSHBUTTON:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Peer using pushbutton");
+               p2p_dbg(p2p, "Peer using pushbutton");
                if (dev->wps_method != WPS_PBC) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: We have wps_method=%s -> "
-                               "incompatible",
+                       p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
                                p2p_wps_method_str(dev->wps_method));
                        status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                        goto fail;
                }
                break;
        default:
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported Device Password ID %d",
+               p2p_dbg(p2p, "Unsupported Device Password ID %d",
                        msg.dev_password_id);
                status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
                goto fail;
        }
 
-       if (go) {
-               struct p2p_channels intersection;
-               size_t i;
-               p2p_channels_intersect(&p2p->channels, &dev->channels,
-                                      &intersection);
-               if (intersection.reg_classes == 0 ||
-                   intersection.reg_class[0].channels == 0) {
-                       status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: No common channels found");
-                       goto fail;
-               }
-               for (i = 0; i < intersection.reg_classes; i++) {
-                       struct p2p_reg_class *c;
-                       c = &intersection.reg_class[i];
-                       wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
-                                  c->reg_class);
-                       wpa_hexdump(MSG_DEBUG, "P2P: channels",
-                                   c->channel, c->channels);
-               }
-               if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
-                                          p2p->op_channel))
-                       p2p_reselect_channel(p2p, &intersection);
-
-               if (!p2p->ssid_set) {
-                       p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
-                       p2p->ssid_set = 1;
-               }
-       }
+       if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+               goto fail;
 
        p2p_set_state(p2p, P2P_GO_NEG);
        p2p_clear_timeout(p2p);
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+       p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
        os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
 
 fail:
@@ -983,8 +1063,7 @@ fail:
        p2p_parse_free(&msg);
        if (conf == NULL)
                return;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending GO Negotiation Confirm");
+       p2p_dbg(p2p, "Sending GO Negotiation Confirm");
        if (status == P2P_SC_SUCCESS) {
                p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
                dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -994,13 +1073,21 @@ fail:
                freq = rx_freq;
        else
                freq = dev->listen_freq;
-       if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
-                           wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+       if (p2p_send_action(p2p, freq, sa,
+#ifdef TIZEN_EXT_P2P
+                           p2p->cfg->own_addr, sa,
+#else
+                           p2p->cfg->dev_addr, sa,
+#endif
+                           wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
+               p2p_dbg(p2p, "Failed to send Action frame");
                p2p_go_neg_failed(p2p, dev, -1);
        }
        wpabuf_free(conf);
+       if (status != P2P_SC_SUCCESS) {
+               p2p_dbg(p2p, "GO Negotiation failed");
+               p2p_go_neg_failed(p2p, dev, status);
+       }
 }
 
 
@@ -1010,22 +1097,18 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
        struct p2p_device *dev;
        struct p2p_message msg;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GO Negotiation Confirm from " MACSTR,
+       p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
                MAC2STR(sa));
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
            dev != p2p->go_neg_peer) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Not ready for GO negotiation with " MACSTR,
+               p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
                        MAC2STR(sa));
                return;
        }
 
        if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopped waiting "
-                       "for TX status on GO Negotiation Response since we "
-                       "already received Confirmation");
+               p2p_dbg(p2p, "Stopped waiting for TX status on GO Negotiation Response since we already received Confirmation");
                p2p->pending_action_state = P2P_NO_PENDING_ACTION;
        }
 
@@ -1033,31 +1116,26 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
                return;
 
        if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Was not expecting GO Negotiation Confirm - "
-                       "ignore");
+               p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
                return;
        }
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
 
        if (msg.dialog_token != dev->dialog_token) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected Dialog Token %u (expected %u)",
+               p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
                        msg.dialog_token, dev->dialog_token);
                p2p_parse_free(&msg);
                return;
        }
 
        if (!msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Status attribute received");
+               p2p_dbg(p2p, "No Status attribute received");
                p2p_parse_free(&msg);
                return;
        }
        if (*msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: GO Negotiation rejected: status %d",
-                       *msg.status);
+               p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
+               p2p_go_neg_failed(p2p, dev, *msg.status);
                p2p_parse_free(&msg);
                return;
        }
@@ -1067,20 +1145,15 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
                p2p->ssid_len = msg.group_id_len - ETH_ALEN;
                os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
        } else if (dev->go_state == REMOTE_GO) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory P2P Group ID attribute missing from "
-                       "GO Negotiation Confirmation");
+               p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
                p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
+               p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
                p2p_parse_free(&msg);
                return;
-#endif /* CONFIG_P2P_STRICT */
        }
 
        if (!msg.operating_channel) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Operating Channel attribute missing "
-                       "from GO Negotiation Confirmation");
+               p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
                p2p_parse_free(&msg);
                return;
@@ -1088,9 +1161,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
        }
 
        if (!msg.channel_list) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Operating Channel attribute missing "
-                       "from GO Negotiation Confirmation");
+               p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
                p2p_parse_free(&msg);
                return;
@@ -1104,11 +1175,20 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
                 * This should not happen since GO negotiation has already
                 * been completed.
                 */
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected GO Neg state - do not know which end "
-                       "becomes GO");
+               p2p_dbg(p2p, "Unexpected GO Neg state - do not know which end becomes GO");
                return;
        }
 
+       /*
+        * The peer could have missed our ctrl::ack frame for GO Negotiation
+        * Confirm and continue retransmitting the frame. To reduce the
+        * likelihood of the peer not getting successful TX status for the
+        * GO Negotiation Confirm frame, wait a short time here before starting
+        * the group so that we will remain on the current channel to
+        * acknowledge any possible retransmission from the peer.
+        */
+       p2p_dbg(p2p, "20 ms wait on current channel before starting group");
+       os_sleep(0, 20000);
+
        p2p_go_complete(p2p, dev);
 }
index 59d1507..15e7622 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P group operations
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -28,6 +22,7 @@ struct p2p_group_member {
        u8 addr[ETH_ALEN]; /* P2P Interface Address */
        u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
        struct wpabuf *p2p_ie;
+       struct wpabuf *wfd_ie;
        struct wpabuf *client_info;
        u8 dev_capab;
 };
@@ -43,12 +38,10 @@ struct p2p_group {
        int group_formation;
        int beacon_update;
        struct wpabuf *noa;
+       struct wpabuf *wfd_ie;
 };
 
 
-static void p2p_group_update_ies(struct p2p_group *group);
-
-
 struct p2p_group * p2p_group_init(struct p2p_data *p2p,
                                  struct p2p_group_config *config)
 {
@@ -58,8 +51,8 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
        if (group == NULL)
                return NULL;
 
-       groups = os_realloc(p2p->groups, (p2p->num_groups + 1) *
-                           sizeof(struct p2p_group *));
+       groups = os_realloc_array(p2p->groups, p2p->num_groups + 1,
+                                 sizeof(struct p2p_group *));
        if (groups == NULL) {
                os_free(group);
                return NULL;
@@ -80,6 +73,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
 
 static void p2p_group_free_member(struct p2p_group_member *m)
 {
+       wpabuf_free(m->wfd_ie);
        wpabuf_free(m->p2p_ie);
        wpabuf_free(m->client_info);
        os_free(m);
@@ -124,6 +118,7 @@ void p2p_group_deinit(struct p2p_group *group)
        p2p_group_free_members(group);
        os_free(group->cfg);
        wpabuf_free(group->noa);
+       wpabuf_free(group->wfd_ie);
        os_free(group);
 }
 
@@ -141,11 +136,10 @@ static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m)
 static void p2p_group_add_common_ies(struct p2p_group *group,
                                     struct wpabuf *ie)
 {
-       u8 dev_capab = 0, group_capab = 0;
+       u8 dev_capab = group->p2p->dev_capab, group_capab = 0;
 
        /* P2P Capability */
-       dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
-       dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
+       dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
        group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
        if (group->cfg->persistent_group) {
                group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -175,15 +169,59 @@ static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
 }
 
 
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+       struct wpabuf *ie;
+       const u8 *pos, *end;
+       size_t len;
+
+       if (subelems == NULL)
+               return NULL;
+
+       len = wpabuf_len(subelems) + 100;
+
+       ie = wpabuf_alloc(len);
+       if (ie == NULL)
+               return NULL;
+
+       pos = wpabuf_head(subelems);
+       end = pos + wpabuf_len(subelems);
+
+       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, P2P_IE_VENDOR_TYPE);
+               wpabuf_put_data(ie, pos, frag_len);
+               pos += frag_len;
+       }
+
+       return ie;
+}
+
+
 static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 {
        struct wpabuf *ie;
        u8 *len;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (group->p2p->wfd_ie_beacon)
+               extra = wpabuf_len(group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       ie = wpabuf_alloc(257);
+       ie = wpabuf_alloc(257 + extra);
        if (ie == NULL)
                return NULL;
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (group->p2p->wfd_ie_beacon)
+               wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        len = p2p_buf_add_ie_hdr(ie);
        p2p_group_add_common_ies(group, ie);
        p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -194,44 +232,222 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 }
 
 
-static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+#ifdef CONFIG_WIFI_DISPLAY
+
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g)
+{
+       return g->wfd_ie;
+}
+
+
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems)
 {
-       u8 *group_info;
        struct wpabuf *ie;
+       const u8 *pos, *end;
+
+       if (subelems == NULL)
+               return NULL;
+
+       ie = wpabuf_alloc(wpabuf_len(subelems) + 100);
+       if (ie == NULL)
+               return NULL;
+
+       pos = wpabuf_head(subelems);
+       end = pos + wpabuf_len(subelems);
+
+       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, WFD_IE_VENDOR_TYPE);
+               wpabuf_put_data(ie, pos, frag_len);
+               pos += frag_len;
+       }
+
+       return ie;
+}
+
+
+static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
+                                          struct p2p_group_member *m)
+{
+       const u8 *pos, *end;
+       const u8 *dev_info = NULL;
+       const u8 *assoc_bssid = NULL;
+       const u8 *coupled_sink = NULL;
+       u8 zero_addr[ETH_ALEN];
+
+       if (m->wfd_ie == NULL)
+               return 0;
+
+       os_memset(zero_addr, 0, ETH_ALEN);
+       pos = wpabuf_head_u8(m->wfd_ie);
+       end = pos + wpabuf_len(m->wfd_ie);
+       while (pos + 1 < end) {
+               u8 id;
+               u16 len;
+
+               id = *pos++;
+               len = WPA_GET_BE16(pos);
+               pos += 2;
+               if (pos + len > end)
+                       break;
+
+               switch (id) {
+               case WFD_SUBELEM_DEVICE_INFO:
+                       if (len < 6)
+                               break;
+                       dev_info = pos;
+                       break;
+               case WFD_SUBELEM_ASSOCIATED_BSSID:
+                       if (len < ETH_ALEN)
+                               break;
+                       assoc_bssid = pos;
+                       break;
+               case WFD_SUBELEM_COUPLED_SINK:
+                       if (len < 1 + ETH_ALEN)
+                               break;
+                       coupled_sink = pos;
+                       break;
+               }
+
+               pos += len;
+       }
+
+       if (dev_info == NULL)
+               return 0;
+
+       wpabuf_put_u8(buf, 23);
+       wpabuf_put_data(buf, m->dev_addr, ETH_ALEN);
+       if (assoc_bssid)
+               wpabuf_put_data(buf, assoc_bssid, ETH_ALEN);
+       else
+               wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+       wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */
+       wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */
+       if (coupled_sink) {
+               wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN);
+       } else {
+               wpabuf_put_u8(buf, 0);
+               wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+       }
+
+       return 1;
+}
+
+
+static struct wpabuf *
+wifi_display_build_go_ie(struct p2p_group *group)
+{
+       struct wpabuf *wfd_subelems, *wfd_ie;
        struct p2p_group_member *m;
        u8 *len;
+       unsigned int count = 0;
 
-       ie = wpabuf_alloc(257);
-       if (ie == NULL)
+       if (!group->p2p->wfd_ie_probe_resp)
                return NULL;
 
-       len = p2p_buf_add_ie_hdr(ie);
+       wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) +
+                                   group->num_members * 24 + 100);
+       if (wfd_subelems == NULL)
+               return NULL;
+       if (group->p2p->wfd_dev_info)
+               wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
+       if (group->p2p->wfd_assoc_bssid)
+               wpabuf_put_buf(wfd_subelems,
+                              group->p2p->wfd_assoc_bssid);
+       if (group->p2p->wfd_coupled_sink_info)
+               wpabuf_put_buf(wfd_subelems,
+                              group->p2p->wfd_coupled_sink_info);
+
+       /* Build WFD Session Info */
+       wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO);
+       len = wpabuf_put(wfd_subelems, 2);
+       m = group->members;
+       while (m) {
+               if (wifi_display_add_dev_info_descr(wfd_subelems, m))
+                       count++;
+               m = m->next;
+       }
 
-       p2p_group_add_common_ies(group, ie);
-       p2p_group_add_noa(ie, group->noa);
+       if (count == 0) {
+               /* No Wi-Fi Display clients - do not include subelement */
+               wfd_subelems->used -= 3;
+       } else {
+               WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
+                            2);
+               p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors",
+                       count);
+       }
+
+       wfd_ie = wifi_display_encaps(wfd_subelems);
+       wpabuf_free(wfd_subelems);
+
+       return wfd_ie;
+}
+
+static void wifi_display_group_update(struct p2p_group *group)
+{
+       wpabuf_free(group->wfd_ie);
+       group->wfd_ie = wifi_display_build_go_ie(group);
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+{
+       struct wpabuf *p2p_subelems, *ie;
+       struct p2p_group_member *m;
+
+       p2p_subelems = wpabuf_alloc(500);
+       if (p2p_subelems == NULL)
+               return NULL;
+
+       p2p_group_add_common_ies(group, p2p_subelems);
+       p2p_group_add_noa(p2p_subelems, group->noa);
 
        /* P2P Device Info */
-       p2p_buf_add_device_info(ie, group->p2p, NULL);
+       p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
+
+       /* P2P Group Info: Only when at least one P2P Client is connected */
+       if (group->members) {
+               u8 *group_info;
+               group_info = wpabuf_put(p2p_subelems, 0);
+               wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+               wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
+               for (m = group->members; m; m = m->next)
+                       p2p_client_info(p2p_subelems, m);
+               WPA_PUT_LE16(group_info + 1,
+                            (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
+                            3);
+       }
 
-       /* P2P Group Info */
-       group_info = wpabuf_put(ie, 0);
-       wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
-       wpabuf_put_le16(ie, 0); /* Length to be filled */
-       for (m = group->members; m; m = m->next)
-               p2p_client_info(ie, m);
-       WPA_PUT_LE16(group_info + 1,
-                    (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+       ie = p2p_group_encaps_probe_resp(p2p_subelems);
+       wpabuf_free(p2p_subelems);
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (group->wfd_ie) {
+               struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
+               ie = wpabuf_concat(wfd, ie);
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       p2p_buf_update_ie_hdr(ie, len);
        return ie;
 }
 
 
-static void p2p_group_update_ies(struct p2p_group *group)
+void p2p_group_update_ies(struct p2p_group *group)
 {
        struct wpabuf *beacon_ie;
        struct wpabuf *probe_resp_ie;
 
+#ifdef CONFIG_WIFI_DISPLAY
+       wifi_display_group_update(group);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        probe_resp_ie = p2p_group_build_probe_resp_ie(group);
        if (probe_resp_ie == NULL)
                return;
@@ -351,6 +567,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
        if (group == NULL)
                return -1;
 
+       p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0);
+
        m = os_zalloc(sizeof(*m));
        if (m == NULL)
                return -1;
@@ -361,15 +579,19 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
                                                       &m->dev_capab,
                                                       m->dev_addr);
        }
+#ifdef CONFIG_WIFI_DISPLAY
+       m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE);
+#endif /* CONFIG_WIFI_DISPLAY */
 
        p2p_group_remove_member(group, addr);
 
        m->next = group->members;
        group->members = m;
        group->num_members++;
-       wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
-               " to group (p2p=%d client_info=%d); num_members=%u/%u",
-               MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0,
+       p2p_dbg(group->p2p,  "Add client " MACSTR
+               " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
+               MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
+               m->client_info ? 1 : 0,
                group->num_members, group->cfg->max_clients);
        if (group->num_members == group->cfg->max_clients)
                group->beacon_update = 1;
@@ -385,6 +607,12 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
 {
        struct wpabuf *resp;
        u8 *rlen;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (group->wfd_ie)
+               extra = wpabuf_len(group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
 
        /*
         * (Re)Association Response - P2P IE
@@ -392,9 +620,15 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
         *      denied)
         * Extended Listen Timing (may be present)
         */
-       resp = wpabuf_alloc(20);
+       resp = wpabuf_alloc(20 + extra);
        if (resp == NULL)
                return NULL;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (group->wfd_ie)
+               wpabuf_put_buf(resp, group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        rlen = p2p_buf_add_ie_hdr(resp);
        if (status != P2P_SC_SUCCESS)
                p2p_buf_add_status(resp, status);
@@ -407,8 +641,8 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
 void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
 {
        if (p2p_group_remove_member(group, addr)) {
-               wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
-                       "client " MACSTR " from group; num_members=%u/%u",
+               p2p_dbg(group->p2p, "Remove client " MACSTR
+                       " from group; num_members=%u/%u",
                        MAC2STR(addr), group->num_members,
                        group->cfg->max_clients);
                if (group->num_members == group->cfg->max_clients - 1)
@@ -490,6 +724,31 @@ int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps)
 }
 
 
+int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p)
+{
+       struct p2p_group_member *m;
+       struct p2p_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       if (p2p_parse_p2p_ie(p2p, &msg))
+               return 1; /* Failed to parse - assume no filter on Device ID */
+
+       if (!msg.device_id)
+               return 1; /* No filter on Device ID */
+
+       if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0)
+               return 1; /* Match with our P2P Device Address */
+
+       for (m = group->members; m; m = m->next) {
+               if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0)
+                       return 1; /* Match with group client P2P Device Address */
+       }
+
+       /* No match with Device ID */
+       return 0;
+}
+
+
 void p2p_group_notif_formation_done(struct p2p_group *group)
 {
        if (group == NULL)
@@ -595,20 +854,18 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
 
        m = p2p_group_get_client(group, dev_id);
        if (m == NULL || m->client_info == NULL) {
-               wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
-                          "group " MACSTR,
-                          MAC2STR(group->cfg->interface_addr));
+               p2p_dbg(group->p2p, "Requested client was not in this group "
+                       MACSTR, MAC2STR(group->cfg->interface_addr));
                return -1;
        }
 
        if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-               wpa_printf(MSG_DEBUG, "P2P: Requested client does not support "
-                          "client discoverability");
+               p2p_dbg(group->p2p, "Requested client does not support client discoverability");
                return -1;
        }
 
-       wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be "
-                  "sent to " MACSTR, MAC2STR(dev_id));
+       p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to "
+               MACSTR, MAC2STR(dev_id));
 
        req = p2p_build_go_disc_req();
        if (req == NULL)
@@ -623,8 +880,7 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
                                  group->cfg->interface_addr,
                                  wpabuf_head(req), wpabuf_len(req), 200) < 0)
        {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
 
        wpabuf_free(req);
@@ -649,7 +905,7 @@ u8 p2p_group_presence_req(struct p2p_group *group,
 
        m = p2p_group_get_client_iface(group, client_interface_addr);
        if (m == NULL || m->client_info == NULL) {
-               wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
+               p2p_dbg(group->p2p, "Client was not in this group");
                return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
        }
 
@@ -662,9 +918,9 @@ u8 p2p_group_presence_req(struct p2p_group *group,
        else
                curr_noa_len = -1;
        if (curr_noa_len < 0)
-               wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
+               p2p_dbg(group->p2p, "Failed to fetch current NoA");
        else if (curr_noa_len == 0)
-               wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
+               p2p_dbg(group->p2p, "No NoA being advertized");
        else
                wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
                            curr_noa_len);
@@ -699,3 +955,28 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
 
        return iter->addr;
 }
+
+
+int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr)
+{
+       struct p2p_group_member *m;
+
+       for (m = group->members; m; m = m->next) {
+               if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+                               size_t group_id_len)
+{
+       if (group_id_len != ETH_ALEN + group->cfg->ssid_len)
+               return 0;
+       if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0)
+               return 0;
+       return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
+                        group->cfg->ssid_len) == 0;
+}
index 0dc33e7..75c1511 100644 (file)
@@ -2,14 +2,8 @@
  * P2P - Internal definitions for P2P module
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef P2P_I_H
@@ -58,6 +52,7 @@ struct p2p_device {
        int go_neg_req_sent;
        enum p2p_go_state go_state;
        u8 dialog_token;
+       u8 tie_breaker;
        u8 intended_addr[ETH_ALEN];
 
        char country[3];
@@ -96,6 +91,8 @@ struct p2p_device {
 #define P2P_DEV_PD_FOR_JOIN BIT(14)
 #define P2P_DEV_REPORTED_ONCE BIT(15)
 #define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
+#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
+#define P2P_DEV_NO_PREF_CHAN BIT(18)
        unsigned int flags;
 
        int status; /* enum p2p_status_code */
@@ -114,6 +111,7 @@ struct p2p_sd_query {
        struct p2p_sd_query *next;
        u8 peer[ETH_ALEN];
        int for_all_peers;
+       int wsd; /* Wi-Fi Display Service Discovery Request */
        struct wpabuf *tlvs;
 };
 
@@ -212,6 +210,11 @@ struct p2p_data {
                 * P2P_SEARCH_WHEN_READY - Waiting to start Search
                 */
                P2P_SEARCH_WHEN_READY,
+
+               /**
+                * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
+                */
+               P2P_CONTINUE_SEARCH_WHEN_READY,
        } state;
 
        /**
@@ -225,6 +228,11 @@ struct p2p_data {
        int max_disc_int;
 
        /**
+        * max_disc_tu - Maximum number of TUs for discoverable interval
+        */
+       int max_disc_tu;
+
+       /**
         * devices - List of known P2P Device peers
         */
        struct dl_list devices;
@@ -377,10 +385,15 @@ struct p2p_data {
        } start_after_scan;
        u8 after_scan_peer[ETH_ALEN];
        struct p2p_pending_action_tx *after_scan_tx;
+       unsigned int after_scan_tx_in_progress:1;
 
        /* Requested device types for find/search */
        unsigned int num_req_dev_types;
        u8 *req_dev_types;
+       u8 *find_dev_id;
+       u8 find_dev_id_buf[ETH_ALEN];
+
+       struct os_time find_start; /* time of last p2p_find start */
 
        struct p2p_group **groups;
        size_t num_groups;
@@ -405,6 +418,7 @@ struct p2p_data {
        int best_freq_24;
        int best_freq_5;
        int best_freq_overall;
+       int own_freq_preference;
 
        /**
         * wps_vendor_ext - WPS Vendor Extensions to add
@@ -427,6 +441,27 @@ struct p2p_data {
         * in IDLE state.
         */
        int pd_retries;
+
+       u8 go_timeout;
+       u8 client_timeout;
+
+       /* Extra delay in milliseconds between search iterations */
+       unsigned int search_delay;
+       int in_search_delay;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       struct wpabuf *wfd_ie_beacon;
+       struct wpabuf *wfd_ie_probe_req;
+       struct wpabuf *wfd_ie_probe_resp;
+       struct wpabuf *wfd_ie_assoc_req;
+       struct wpabuf *wfd_ie_invitation;
+       struct wpabuf *wfd_ie_prov_disc_req;
+       struct wpabuf *wfd_ie_prov_disc_resp;
+       struct wpabuf *wfd_ie_go_neg;
+       struct wpabuf *wfd_dev_info;
+       struct wpabuf *wfd_assoc_bssid;
+       struct wpabuf *wfd_coupled_sink_info;
+#endif /* CONFIG_WIFI_DISPLAY */
 };
 
 /**
@@ -435,6 +470,7 @@ struct p2p_data {
 struct p2p_message {
        struct wpabuf *p2p_attributes;
        struct wpabuf *wps_attributes;
+       struct wpabuf *wfd_subelems;
 
        u8 dialog_token;
 
@@ -521,9 +557,8 @@ struct p2p_group_info {
 
 /* p2p_utils.c */
 int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-                       u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
 void p2p_channels_intersect(const struct p2p_channels *a,
                            const struct p2p_channels *b,
                            struct p2p_channels *res);
@@ -553,6 +588,10 @@ const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
 u8 p2p_group_presence_req(struct p2p_group *group,
                          const u8 *client_interface_addr,
                          const u8 *noa, size_t noa_len);
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+                               size_t group_id_len);
+void p2p_group_update_ies(struct p2p_group *group);
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
 
 
 void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -584,7 +623,7 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
 void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
                                   u16 interval);
 void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
                      int all_attr);
 
 /* p2p_sd.c */
@@ -612,7 +651,13 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
 void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
                             const u8 *data, size_t len);
 int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
+void p2p_reselect_channel(struct p2p_data *p2p,
+                         struct p2p_channels *intersection);
 
+#ifdef TIZEN_EXT_P2P
+int p2p_reject_send(struct p2p_data *p2p, struct p2p_device *dev);
+#endif
 /* p2p_pd.c */
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                               const u8 *data, size_t len, int rx_freq);
@@ -655,6 +700,9 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
                                                struct p2p_message *msg);
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
                      struct p2p_device *dev, struct p2p_message *msg);
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+                  struct os_time *rx_time, int level, const u8 *ies,
+                  size_t ies_len, int scan_res);
 struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
 struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
                                             const u8 *addr);
@@ -669,5 +717,14 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
 int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                    const u8 *src, const u8 *bssid, const u8 *buf,
                    size_t len, unsigned int wait_time);
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+                       unsigned int force_freq, unsigned int pref_freq);
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
 
 #endif /* P2P_I_H */
index bb2767d..10ab430 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P Invitation procedure
  * Copyright (c) 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -27,8 +21,30 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
        struct wpabuf *buf;
        u8 *len;
        const u8 *dev_addr;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+       if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       struct p2p_group *g = p2p->groups[i];
+                       struct wpabuf *ie;
+                       if (os_memcmp(p2p_group_get_interface_addr(g),
+                                     p2p->inv_bssid, ETH_ALEN) != 0)
+                               continue;
+                       ie = p2p_group_get_wfd_ie(g);
+                       if (ie) {
+                               wfd_ie = ie;
+                               break;
+                       }
+               }
+       }
+       if (wfd_ie)
+               extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(1000);
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -42,11 +58,15 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
        if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent)
                p2p_buf_add_config_timeout(buf, 0, 0);
        else
-               p2p_buf_add_config_timeout(buf, 100, 20);
+               p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+                                          p2p->client_timeout);
        p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
                                     P2P_INVITATION_FLAGS_TYPE : 0);
-       p2p_buf_add_operating_channel(buf, p2p->cfg->country,
-                                     p2p->op_reg_class, p2p->op_channel);
+       if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
+           !(peer->flags & P2P_DEV_NO_PREF_CHAN))
+               p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+                                             p2p->op_reg_class,
+                                             p2p->op_channel);
        if (p2p->inv_bssid_set)
                p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
        p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
@@ -60,6 +80,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
        p2p_buf_add_device_info(buf, p2p, peer);
        p2p_buf_update_ie_hdr(buf, len);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wfd_ie)
+               wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -73,8 +98,30 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
 {
        struct wpabuf *buf;
        u8 *len;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+       if (wfd_ie && group_bssid) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       struct p2p_group *g = p2p->groups[i];
+                       struct wpabuf *ie;
+                       if (os_memcmp(p2p_group_get_interface_addr(g),
+                                     group_bssid, ETH_ALEN) != 0)
+                               continue;
+                       ie = p2p_group_get_wfd_ie(g);
+                       if (ie) {
+                               wfd_ie = ie;
+                               break;
+                       }
+               }
+       }
+       if (wfd_ie)
+               extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(1000);
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -93,6 +140,11 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
                p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
        p2p_buf_update_ie_hdr(buf, len);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wfd_ie)
+               wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -114,8 +166,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
 
        os_memset(group_bssid, 0, sizeof(group_bssid));
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Invitation Request from " MACSTR " (freq=%d)",
+       p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)",
                MAC2STR(sa), rx_freq);
 
        if (p2p_parse(data, len, &msg))
@@ -123,13 +174,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invitation Request from unknown peer "
-                       MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR,
+                       MAC2STR(sa));
 
-               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Invitation Request add device failed "
+               if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
+                                  0)) {
+                       p2p_dbg(p2p, "Invitation Request add device failed "
                                MACSTR, MAC2STR(sa));
                        status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
                        goto fail;
@@ -137,18 +187,16 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
 
                dev = p2p_get_device(p2p, sa);
                if (dev == NULL) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Reject Invitation Request from unknown "
-                               "peer " MACSTR, MAC2STR(sa));
+                       p2p_dbg(p2p, "Reject Invitation Request from unknown peer "
+                               MACSTR, MAC2STR(sa));
                        status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
                        goto fail;
                }
        }
 
        if (!msg.group_id || !msg.channel_list) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory attribute missing in Invitation "
-                       "Request from " MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from "
+                       MACSTR, MAC2STR(sa));
                status = P2P_SC_FAIL_INVALID_PARAMS;
                goto fail;
        }
@@ -161,44 +209,42 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                 * the request was for a persistent group if the attribute is
                 * missing.
                 */
-               wpa_printf(MSG_DEBUG, "P2P: Mandatory Invitation Flags "
-                          "attribute missing from Invitation Request");
+               p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request");
                persistent = 1;
        }
 
        if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
                                    msg.channel_list, msg.channel_list_len) <
            0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No common channels found");
+               p2p_dbg(p2p, "No common channels found");
                status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                goto fail;
        }
 
+       p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+                              &intersection);
+
        if (p2p->cfg->invitation_process) {
                status = p2p->cfg->invitation_process(
                        p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
                        msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
-                       &go, group_bssid, &op_freq, persistent);
+                       &go, group_bssid, &op_freq, persistent, &intersection);
        }
 
        if (op_freq) {
-               if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
-                                       &reg_class, &channel) < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unknown forced freq %d MHz from "
-                               "invitation_process()", op_freq);
+               p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
+                       op_freq);
+               if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
+                       p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()",
+                               op_freq);
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
                }
 
-               p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-                                      &intersection);
                if (!p2p_channels_includes(&intersection, reg_class, channel))
                {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: forced freq %d MHz not in the supported "
-                               "channels interaction", op_freq);
+                       p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+                               op_freq);
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
                }
@@ -206,24 +252,71 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                if (status == P2P_SC_SUCCESS)
                        channels = &intersection;
        } else {
-               op_freq = p2p_channel_to_freq(p2p->cfg->country,
-                                             p2p->cfg->op_reg_class,
-                                             p2p->cfg->op_channel);
+               p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
+
+               /* Default to own configuration as a starting point */
+               p2p->op_reg_class = p2p->cfg->op_reg_class;
+               p2p->op_channel = p2p->cfg->op_channel;
+               p2p_dbg(p2p, "Own default op_class %d channel %d",
+                       p2p->op_reg_class, p2p->op_channel);
+
+               /* Use peer preference if specified and compatible */
+               if (msg.operating_channel) {
+                       int req_freq;
+                       req_freq = p2p_channel_to_freq(
+                               msg.operating_channel[3],
+                               msg.operating_channel[4]);
+                       p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+                               req_freq);
+                       if (req_freq > 0 &&
+                           p2p_channels_includes(&intersection,
+                                                 msg.operating_channel[3],
+                                                 msg.operating_channel[4])) {
+                               p2p->op_reg_class = msg.operating_channel[3];
+                               p2p->op_channel = msg.operating_channel[4];
+                               p2p_dbg(p2p, "Use peer preference op_class %d channel %d",
+                                       p2p->op_reg_class, p2p->op_channel);
+                       } else {
+                               p2p_dbg(p2p, "Cannot use peer channel preference");
+                       }
+               }
+
+               if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+                                          p2p->op_channel)) {
+                       p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
+                               p2p->op_reg_class, p2p->op_channel);
+                       p2p_reselect_channel(p2p, &intersection);
+                       p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
+                               p2p->op_reg_class, p2p->op_channel);
+                       if (!p2p_channels_includes(&intersection,
+                                                  p2p->op_reg_class,
+                                                  p2p->op_channel)) {
+                               p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)",
+                                       p2p->op_reg_class, p2p->op_channel);
+                               status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+                               goto fail;
+                       }
+               } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+                          !p2p->cfg->cfg_op_channel) {
+                       p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
+                               p2p->op_reg_class, p2p->op_channel);
+                       p2p_reselect_channel(p2p, &intersection);
+               }
+
+               op_freq = p2p_channel_to_freq(p2p->op_reg_class,
+                                             p2p->op_channel);
                if (op_freq < 0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unknown operational channel "
-                               "(country=%c%c reg_class=%u channel=%u)",
+                       p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)",
                                p2p->cfg->country[0], p2p->cfg->country[1],
-                               p2p->cfg->op_reg_class, p2p->cfg->op_channel);
+                               p2p->op_reg_class, p2p->op_channel);
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
                }
+               p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq);
 
-               p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-                                      &intersection);
                if (status == P2P_SC_SUCCESS) {
-                       reg_class = p2p->cfg->op_reg_class;
-                       channel = p2p->cfg->op_channel;
+                       reg_class = p2p->op_reg_class;
+                       channel = p2p->op_channel;
                        channels = &intersection;
                }
        }
@@ -242,12 +335,10 @@ fail:
        if (rx_freq > 0)
                freq = rx_freq;
        else
-               freq = p2p_channel_to_freq(p2p->cfg->country,
-                                          p2p->cfg->reg_class,
+               freq = p2p_channel_to_freq(p2p->cfg->reg_class,
                                           p2p->cfg->channel);
        if (freq < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown regulatory class/channel");
+               p2p_dbg(p2p, "Unknown regulatory class/channel");
                goto out;
        }
 
@@ -271,11 +362,14 @@ fail:
        p2p->inv_op_freq = op_freq;
 
        p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
-       if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
+       if (p2p_send_action(p2p, freq, sa,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, p2p->cfg->own_addr,
+#else
+                           p2p->cfg->dev_addr, p2p->cfg->dev_addr,
+#endif
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
 
 out:
@@ -289,22 +383,20 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 {
        struct p2p_device *dev;
        struct p2p_message msg;
+       struct p2p_channels intersection, *channels = NULL;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Invitation Response from " MACSTR,
+       p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
                MAC2STR(sa));
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore Invitation Response from unknown peer "
+               p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
                        MACSTR, MAC2STR(sa));
                return;
        }
 
        if (dev != p2p->invite_peer) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore unexpected Invitation Response from peer "
+               p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
                        MACSTR, MAC2STR(sa));
                return;
        }
@@ -313,16 +405,36 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
                return;
 
        if (!msg.status) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Mandatory Status attribute missing in "
-                       "Invitation Response from " MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
+                       MACSTR, MAC2STR(sa));
                p2p_parse_free(&msg);
                return;
        }
 
+       if (!msg.channel_list) {
+               p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
+                       MACSTR, MAC2STR(sa));
+#ifdef CONFIG_P2P_STRICT
+               p2p_parse_free(&msg);
+               return;
+#endif /* CONFIG_P2P_STRICT */
+               /* Try to survive without peer channel list */
+               channels = &p2p->channels;
+       } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
+                                          msg.channel_list,
+                                          msg.channel_list_len) < 0) {
+               p2p_dbg(p2p, "No common channels found");
+               p2p_parse_free(&msg);
+               return;
+       } else {
+               p2p_channels_intersect(&p2p->channels, &dev->channels,
+                                      &intersection);
+               channels = &intersection;
+       }
+
        if (p2p->cfg->invitation_result)
                p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
-                                           msg.group_bssid);
+                                           msg.group_bssid, channels, sa);
 
        p2p_parse_free(&msg);
 
@@ -340,9 +452,8 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
 
        freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
        if (freq <= 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Listen/Operating frequency known for the "
-                       "peer " MACSTR " to send Invitation Request",
+               p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+                       MACSTR " to send Invitation Request",
                        MAC2STR(dev->info.p2p_device_addr));
                return -1;
        }
@@ -350,17 +461,21 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
        req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
        if (req == NULL)
                return -1;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending Invitation Request");
+       if (p2p->state != P2P_IDLE)
+               p2p_stop_listen_for_freq(p2p, freq);
+       p2p_dbg(p2p, "Sending Invitation Request");
        p2p_set_state(p2p, P2P_INVITE);
        p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
        p2p->invite_peer = dev;
        dev->invitation_reqs++;
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+#ifdef TIZEN_EXT_P2P
+                           p2p->cfg->own_addr, dev->info.p2p_device_addr,
+#else
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
+#endif
                            wpabuf_head(req), wpabuf_len(req), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
                /* Use P2P find to recover and retry */
                p2p_set_timeout(p2p, 0, 0);
        }
@@ -373,12 +488,10 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
 
 void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Invitation Request TX callback: success=%d", success);
+       p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success);
 
        if (p2p->invite_peer == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No pending Invite");
+               p2p_dbg(p2p, "No pending Invite");
                return;
        }
 
@@ -387,17 +500,19 @@ void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
         * channel.
         */
        p2p_set_state(p2p, P2P_INVITE);
-       p2p_set_timeout(p2p, 0, 100000);
+       p2p_set_timeout(p2p, 0, success ? 350000 : 100000);
 }
 
 
 void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
 {
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Invitation Response TX callback: success=%d", success);
+       p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
-       if (success && p2p->cfg->invitation_received) {
+       if (!success)
+               p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported");
+
+       if (p2p->cfg->invitation_received) {
                p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
                                              p2p->inv_sa,
                                              p2p->inv_group_bssid_ptr,
@@ -412,41 +527,45 @@ void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
               const u8 *bssid, const u8 *ssid, size_t ssid_len,
               unsigned int force_freq, const u8 *go_dev_addr,
-              int persistent_group)
+              int persistent_group, unsigned int pref_freq)
 {
        struct p2p_device *dev;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Request to invite peer " MACSTR " role=%d persistent=%d "
+       p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
                "force_freq=%u",
                MAC2STR(peer), role, persistent_group, force_freq);
        if (bssid)
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invitation for BSSID " MACSTR, MAC2STR(bssid));
+               p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
        if (go_dev_addr) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invitation for GO Device Address " MACSTR,
+               p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR,
                        MAC2STR(go_dev_addr));
                os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN);
                p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf;
        } else
                p2p->invite_go_dev_addr = NULL;
-       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Invitation for SSID",
+       wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
                          ssid, ssid_len);
 
        dev = p2p_get_device(p2p, peer);
        if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Cannot invite unknown P2P Device " MACSTR,
+               p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
                        MAC2STR(peer));
                return -1;
        }
 
+       if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+               return -1;
+
+       if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
+           !pref_freq)
+               dev->flags |= P2P_DEV_NO_PREF_CHAN;
+       else
+               dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
+
        if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
                if (!(dev->info.dev_capab &
                      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Cannot invite a P2P Device " MACSTR
+                       p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR
                                " that is in a group and is not discoverable",
                                MAC2STR(peer));
                }
@@ -455,26 +574,6 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 
        dev->invitation_reqs = 0;
 
-       if (force_freq) {
-               if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
-                                       &p2p->op_reg_class, &p2p->op_channel) <
-                   0) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Unsupported frequency %u MHz",
-                               force_freq);
-                       return -1;
-               }
-               p2p->channels.reg_classes = 1;
-               p2p->channels.reg_class[0].channels = 1;
-               p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
-               p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
-       } else {
-               p2p->op_reg_class = p2p->cfg->op_reg_class;
-               p2p->op_channel = p2p->cfg->op_channel;
-               os_memcpy(&p2p->channels, &p2p->cfg->channels,
-                         sizeof(struct p2p_channels));
-       }
-
        if (p2p->state != P2P_IDLE)
                p2p_stop_find(p2p);
 
index 5c5445a..097a31d 100644 (file)
@@ -2,14 +2,8 @@
  * P2P - IE parser
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -420,6 +414,13 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
                return -1;
        }
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (elems.wfd) {
+               msg->wfd_subelems = ieee802_11_vendor_ie_concat(
+                       data, len, WFD_IE_VENDOR_TYPE);
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return 0;
 }
 
@@ -459,6 +460,10 @@ void p2p_parse_free(struct p2p_message *msg)
        msg->p2p_attributes = NULL;
        wpabuf_free(msg->wps_attributes);
        msg->wps_attributes = NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+       wpabuf_free(msg->wfd_subelems);
+       msg->wfd_subelems = NULL;
+#endif /* CONFIG_WIFI_DISPLAY */
 }
 
 
index 1ee59c5..c455d01 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P provision discovery
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 
 
 /*
- * Number of retries to attempt for provision discovery requests during IDLE
- * state in case the peer is not listening.
+ * Number of retries to attempt for provision discovery requests
+ * in case the peer is not listening.
  */
-#define MAX_PROV_DISC_REQ_RETRIES 10
+#define MAX_PROV_DISC_REQ_RETRIES 120
 
 
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
@@ -52,15 +46,22 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
 {
        struct wpabuf *buf;
        u8 *len;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_prov_disc_req)
+               extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(1000);
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
        p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
 
        len = p2p_buf_add_ie_hdr(buf);
-       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        p2p_buf_add_device_info(buf, p2p, NULL);
        if (go) {
                p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
@@ -71,17 +72,46 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
        /* WPS IE with Config Methods attribute */
        p2p_build_wps_ie_config_methods(buf, config_methods);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_prov_disc_req)
+               wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
 
 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                                                u8 dialog_token,
-                                               u16 config_methods)
+                                               u16 config_methods,
+                                               const u8 *group_id,
+                                               size_t group_id_len)
 {
        struct wpabuf *buf;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
+       if (wfd_ie && group_id) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       struct p2p_group *g = p2p->groups[i];
+                       struct wpabuf *ie;
+                       if (!p2p_group_is_group_id_match(g, group_id,
+                                                        group_id_len))
+                               continue;
+                       ie = p2p_group_get_wfd_ie(g);
+                       if (ie) {
+                               wfd_ie = ie;
+                               break;
+                       }
+               }
+       }
+       if (wfd_ie)
+               extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(100);
+       buf = wpabuf_alloc(100 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -90,6 +120,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
        /* WPS IE with Config Methods attribute */
        p2p_build_wps_ie_config_methods(buf, config_methods);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wfd_ie)
+               wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -106,41 +141,56 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        if (p2p_parse(data, len, &msg))
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Provision Discovery Request from " MACSTR
+       p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
                " with config methods 0x%x (freq=%d)",
                MAC2STR(sa), msg.wps_config_methods, rx_freq);
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Provision Discovery Request from "
-                       "unknown peer " MACSTR, MAC2STR(sa));
-               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Provision Discovery Request add device "
-                               "failed " MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
+                       MACSTR, MAC2STR(sa));
+
+               if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
+                                  0)) {
+                       p2p_dbg(p2p, "Provision Discovery Request add device failed "
+                               MACSTR, MAC2STR(sa));
                }
+       } else if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
        }
 
        if (!(msg.wps_config_methods &
              (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
               WPS_CONFIG_PUSHBUTTON))) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
-                       "Config Methods in Provision Discovery Request");
+               p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
                goto out;
        }
 
+       if (msg.group_id) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       if (p2p_group_is_group_id_match(p2p->groups[i],
+                                                       msg.group_id,
+                                                       msg.group_id_len))
+                               break;
+               }
+               if (i == p2p->num_groups) {
+                       p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
+                       goto out;
+               }
+       }
+
        if (dev)
                dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
                                P2P_DEV_PD_PEER_KEYPAD);
        if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+               p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to show a PIN on display", MAC2STR(sa));
                if (dev)
                        dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
        } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+               p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to write its PIN using keypad",
                        MAC2STR(sa));
                if (dev)
@@ -151,32 +201,36 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 
 out:
        resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
-                                       reject ? 0 : msg.wps_config_methods);
+                                       reject ? 0 : msg.wps_config_methods,
+                                       msg.group_id, msg.group_id_len);
        if (resp == NULL) {
                p2p_parse_free(&msg);
                return;
        }
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Sending Provision Discovery Response");
+       p2p_dbg(p2p, "Sending Provision Discovery Response");
        if (rx_freq > 0)
                freq = rx_freq;
        else
-               freq = p2p_channel_to_freq(p2p->cfg->country,
-                                          p2p->cfg->reg_class,
+               freq = p2p_channel_to_freq(p2p->cfg->reg_class,
                                           p2p->cfg->channel);
        if (freq < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unknown regulatory class/channel");
+               p2p_dbg(p2p, "Unknown regulatory class/channel");
                wpabuf_free(resp);
                p2p_parse_free(&msg);
                return;
        }
+#ifdef TIZEN_EXT
+       u8 null_mac[ETH_ALEN] = {0, };
+#endif
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
+       if (p2p_send_action(p2p, freq, sa,
+#ifdef TIZEN_EXT_P2P
+                           p2p->cfg->own_addr, null_mac,
+#else
+                           p2p->cfg->dev_addr, p2p->cfg->dev_addr,
+#endif
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
        }
 
        wpabuf_free(resp);
@@ -203,39 +257,42 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
 {
        struct p2p_message msg;
        struct p2p_device *dev;
-       u16 report_config_methods = 0;
+       u16 report_config_methods = 0, req_config_methods;
+       int success = 0;
 
        if (p2p_parse(data, len, &msg))
                return;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received Provision Discovery Response from " MACSTR
+       p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
                " with config methods 0x%x",
                MAC2STR(sa), msg.wps_config_methods);
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || !dev->req_config_methods) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore Provision Discovery Response from "
-                       MACSTR " with no pending request", MAC2STR(sa));
+               p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
+                       " with no pending request", MAC2STR(sa));
                p2p_parse_free(&msg);
                return;
        }
 
-       if (p2p->pending_action_state == P2P_PENDING_PD) {
-               os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
-               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       }
-
        if (dev->dialog_token != msg.dialog_token) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore Provision Discovery Response with "
-                       "unexpected Dialog Token %u (expected %u)",
+               p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
                        msg.dialog_token, dev->dialog_token);
                p2p_parse_free(&msg);
                return;
        }
 
+       if (p2p->pending_action_state == P2P_PENDING_PD) {
+               os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       }
+
+       /*
+        * Use a local copy of the requested config methods since
+        * p2p_reset_pending_pd() can clear this in the peer entry.
+        */
+       req_config_methods = dev->req_config_methods;
+
        /*
         * If the response is from the peer to whom a user initiated request
         * was sent earlier, we reset that state info here.
@@ -244,9 +301,9 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
            os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
                p2p_reset_pending_pd(p2p);
 
-       if (msg.wps_config_methods != dev->req_config_methods) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
-                       "our Provision Discovery Request");
+       if (msg.wps_config_methods != req_config_methods) {
+               p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
+                       msg.wps_config_methods, req_config_methods);
                if (p2p->cfg->prov_disc_fail)
                        p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
                                                 P2P_PROV_DISC_REJECTED);
@@ -254,15 +311,15 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                goto out;
        }
 
-       report_config_methods = dev->req_config_methods;
+       report_config_methods = req_config_methods;
        dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
                        P2P_DEV_PD_PEER_KEYPAD);
-       if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+       if (req_config_methods & WPS_CONFIG_DISPLAY) {
+               p2p_dbg(p2p, "Peer " MACSTR
                        " accepted to show a PIN on display", MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
        } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+               p2p_dbg(p2p, "Peer " MACSTR
                        " accepted to write our PIN using keypad",
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
@@ -272,13 +329,26 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        dev->wps_prov_info = msg.wps_config_methods;
 
        p2p_parse_free(&msg);
+       success = 1;
 
 out:
        dev->req_config_methods = 0;
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-       if (p2p->cfg->prov_disc_resp)
+       if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+               p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
+                       MACSTR, MAC2STR(dev->info.p2p_device_addr));
+               dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+               p2p_connect_send(p2p, dev);
+               return;
+       }
+       if (success && p2p->cfg->prov_disc_resp)
                p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
                                         report_config_methods);
+
+       if (p2p->state == P2P_PD_DURING_FIND) {
+               p2p_clear_timeout(p2p);
+               p2p_continue_find(p2p);
+       }
 }
 
 
@@ -294,9 +364,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
                freq = dev->listen_freq > 0 ? dev->listen_freq :
                        dev->oper_freq;
        if (freq <= 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Listen/Operating frequency known for the "
-                       "peer " MACSTR " to send Provision Discovery Request",
+               p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+                       MACSTR " to send Provision Discovery Request",
                        MAC2STR(dev->info.p2p_device_addr));
                return -1;
        }
@@ -304,8 +373,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
        if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
                if (!(dev->info.dev_capab &
                      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Cannot use PD with P2P Device " MACSTR
+                       p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
                                " that is in a group and is not discoverable",
                                MAC2STR(dev->info.p2p_device_addr));
                        return -1;
@@ -313,21 +381,23 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
                /* TODO: use device discoverability request through GO */
        }
 
-       dev->dialog_token++;
-       if (dev->dialog_token == 0)
-               dev->dialog_token = 1;
        req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
                                      dev->req_config_methods,
                                      join ? dev : NULL);
        if (req == NULL)
                return -1;
 
+       if (p2p->state != P2P_IDLE)
+               p2p_stop_listen_for_freq(p2p, freq);
        p2p->pending_action_state = P2P_PENDING_PD;
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+#ifdef TIZEN_EXT_P2P
+                           p2p->cfg->own_addr, dev->info.p2p_device_addr,
+#else
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
+#endif
                            wpabuf_head(req), wpabuf_len(req), 200) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
                wpabuf_free(req);
                return -1;
        }
@@ -340,7 +410,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-                     u16 config_methods, int join, int force_freq)
+                     u16 config_methods, int join, int force_freq,
+                     int user_initiated_pd)
 {
        struct p2p_device *dev;
 
@@ -348,14 +419,13 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
        if (dev == NULL)
                dev = p2p_get_device_interface(p2p, peer_addr);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
-                       "Discovery Request destination " MACSTR
+               p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
                        " not yet known", MAC2STR(peer_addr));
                return -1;
        }
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
-               "Request with " MACSTR " (config methods 0x%x)",
+       p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
+               " (config methods 0x%x)",
                MAC2STR(peer_addr), config_methods);
        if (config_methods == 0)
                return -1;
@@ -369,26 +439,27 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
        else
                dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
 
-       if (p2p->go_neg_peer ||
-           (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
-            p2p->state != P2P_LISTEN_ONLY)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
-                       "operations; postpone Provision Discovery Request "
-                       "with " MACSTR " (config methods 0x%x)",
+       if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
+           p2p->state != P2P_LISTEN_ONLY) {
+               p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
+                       MACSTR " (config methods 0x%x)",
                        MAC2STR(peer_addr), config_methods);
                return 0;
        }
 
-       /*
-        * We use the join param as a cue to differentiate between user
-        * initiated PD request and one issued during finds (internal).
-        */
-       p2p->user_initiated_pd = !join;
+       p2p->user_initiated_pd = user_initiated_pd;
 
-       /* Also set some retries to attempt in case of IDLE state */
-       if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+       if (p2p->user_initiated_pd)
                p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
 
+       /*
+        * Assign dialog token here to use the same value in each retry within
+        * the same PD exchange.
+        */
+       dev->dialog_token++;
+       if (dev->dialog_token == 0)
+               dev->dialog_token = 1;
+
        return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
 }
 
index f53d4b5..baa8bea 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Direct - P2P service discovery
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "p2p.h"
 
 
+#ifdef CONFIG_WIFI_DISPLAY
+static int wfd_wsd_supported(struct wpabuf *wfd)
+{
+       const u8 *pos, *end;
+       u8 subelem;
+       u16 len;
+
+       if (wfd == NULL)
+               return 0;
+
+       pos = wpabuf_head(wfd);
+       end = pos + wpabuf_len(wfd);
+
+       while (pos + 3 <= end) {
+               subelem = *pos++;
+               len = WPA_GET_BE16(pos);
+               pos += 2;
+               if (pos + len > end)
+                       break;
+
+               if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
+                       u16 info = WPA_GET_BE16(pos);
+                       return !!(info & 0x0040);
+               }
+
+               pos += len;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
 struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
                                         struct p2p_device *dev)
 {
        struct p2p_sd_query *q;
+       int wsd = 0;
 
        if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
                return NULL; /* peer does not support SD */
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wfd_wsd_supported(dev->info.wfd_subelems))
+               wsd = 1;
+#endif /* CONFIG_WIFI_DISPLAY */
 
        for (q = p2p->sd_queries; q; q = q->next) {
+               /* Use WSD only if the peer indicates support or it */
+               if (q->wsd && !wsd)
+                       continue;
                if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
                        return q;
                if (!q->for_all_peers &&
@@ -121,10 +155,14 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
                return;
 
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
+       if (p2p_send_action(p2p, freq, dst,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, dst,
+#else
+                           p2p->cfg->dev_addr, dst,
+#endif
                            wpabuf_head(req), wpabuf_len(req), 200) < 0)
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
 
        wpabuf_free(req);
 }
@@ -201,9 +239,8 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
 
        freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
        if (freq <= 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: No Listen/Operating frequency known for the "
-                       "peer " MACSTR " to send SD Request",
+               p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+                       MACSTR " to send SD Request",
                        MAC2STR(dev->info.p2p_device_addr));
                return -1;
        }
@@ -212,8 +249,7 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
        if (query == NULL)
                return -1;
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Start Service Discovery with " MACSTR,
+       p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
                MAC2STR(dev->info.p2p_device_addr));
 
        req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
@@ -225,10 +261,13 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
        p2p->pending_action_state = P2P_PENDING_SD;
 
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, dev->info.p2p_device_addr,
+#else
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
+#endif
                            wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
                ret = -1;
        }
 
@@ -256,8 +295,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        if (rx_freq > 0)
                freq = rx_freq;
        else
-               freq = p2p_channel_to_freq(p2p->cfg->country,
-                                          p2p->cfg->reg_class,
+               freq = p2p_channel_to_freq(p2p->cfg->reg_class,
                                           p2p->cfg->channel);
        if (freq < 0)
                return;
@@ -266,14 +304,12 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
                return;
 
        dialog_token = *pos++;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: GAS Initial Request from " MACSTR " (dialog token %u, "
-               "freq %d)",
+       p2p_dbg(p2p, "GAS Initial Request from " MACSTR
+               " (dialog token %u, freq %d)",
                MAC2STR(sa), dialog_token, rx_freq);
 
        if (*pos != WLAN_EID_ADV_PROTO) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected IE in GAS Initial Request: %u", *pos);
+               p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
                return;
        }
        pos++;
@@ -281,15 +317,13 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        slen = *pos++;
        next = pos + slen;
        if (next > end || slen < 2) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid IE in GAS Initial Request");
+               p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
                return;
        }
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported GAS advertisement protocol id %u",
+               p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
                        *pos);
                return;
        }
@@ -308,8 +342,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        if (pos + 4 > end)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+               p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
                return;
        }
        pos += 2;
@@ -317,21 +350,18 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        slen = WPA_GET_LE16(pos);
        pos += 2;
        if (pos + slen > end || slen < 3 + 1) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid ANQP Query Request length");
+               p2p_dbg(p2p, "Invalid ANQP Query Request length");
                return;
        }
 
        if (WPA_GET_BE24(pos) != OUI_WFA) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+               p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
                return;
        }
        pos += 3;
 
        if (*pos != P2P_OUI_TYPE) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
                return;
        }
        pos++;
@@ -339,8 +369,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        if (pos + 2 > end)
                return;
        update_indic = WPA_GET_LE16(pos);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Service Update Indicator: %u", update_indic);
+       p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
        pos += 2;
 
        p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
@@ -356,8 +385,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
 
        /* TODO: fix the length limit to match with the maximum frame length */
        if (wpabuf_len(resp_tlvs) > 1400) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response long "
-                       "enough to require fragmentation");
+               p2p_dbg(p2p, "SD response long enough to require fragmentation");
                if (p2p->sd_resp) {
                        /*
                         * TODO: Could consider storing the fragmented response
@@ -366,20 +394,22 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
                         * Though, that would eat more memory, so there are
                         * also benefits to just using a single buffer.
                         */
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
-                               "previous SD response");
+                       p2p_dbg(p2p, "Drop previous SD response");
                        wpabuf_free(p2p->sd_resp);
                }
+               p2p->sd_resp = wpabuf_dup(resp_tlvs);
+               if (p2p->sd_resp == NULL) {
+                       p2p_err(p2p, "Failed to allocate SD response fragmentation area");
+                       return;
+               }
                os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
                p2p->sd_resp_dialog_token = dialog_token;
-               p2p->sd_resp = wpabuf_dup(resp_tlvs);
                p2p->sd_resp_pos = 0;
                p2p->sd_frag_id = 0;
                resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
                                             1, p2p->srv_update_indic, NULL);
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response fits "
-                       "in initial response");
+               p2p_dbg(p2p, "SD response fits in initial response");
                resp = p2p_build_sd_response(dialog_token,
                                             WLAN_STATUS_SUCCESS, 0,
                                             p2p->srv_update_indic, resp_tlvs);
@@ -388,11 +418,14 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
                return;
 
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
+       if (p2p_send_action(p2p, freq, dst,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, p2p->cfg->own_addr,
+#else
+                           p2p->cfg->dev_addr, p2p->cfg->dev_addr,
+#endif
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
 
        wpabuf_free(resp);
 }
@@ -412,21 +445,18 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
 
        if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
            os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore unexpected GAS Initial Response from "
+               p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
                        MACSTR, MAC2STR(sa));
                return;
        }
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
        p2p_clear_timeout(p2p);
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GAS Initial Response from " MACSTR " (len=%d)",
+       p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
                MAC2STR(sa), (int) len);
 
        if (len < 5 + 2) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Too short GAS Initial Response frame");
+               p2p_dbg(p2p, "Too short GAS Initial Response frame");
                return;
        }
 
@@ -436,20 +466,16 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        pos += 2;
        comeback_delay = WPA_GET_LE16(pos);
        pos += 2;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: dialog_token=%u status_code=%u comeback_delay=%u",
+       p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
                dialog_token, status_code, comeback_delay);
        if (status_code) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Service Discovery failed: status code %u",
+               p2p_dbg(p2p, "Service Discovery failed: status code %u",
                        status_code);
                return;
        }
 
        if (*pos != WLAN_EID_ADV_PROTO) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected IE in GAS Initial Response: %u",
-                       *pos);
+               p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
                return;
        }
        pos++;
@@ -457,15 +483,13 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        slen = *pos++;
        next = pos + slen;
        if (next > end || slen < 2) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid IE in GAS Initial Response");
+               p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
                return;
        }
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported GAS advertisement protocol id %u",
+               p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
                        *pos);
                return;
        }
@@ -473,27 +497,22 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        pos = next;
        /* Query Response */
        if (pos + 2 > end) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
-                       "Response");
+               p2p_dbg(p2p, "Too short Query Response");
                return;
        }
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
-               slen);
+       p2p_dbg(p2p, "Query Response Length: %d", slen);
        if (pos + slen > end) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
-                       "Response data");
+               p2p_dbg(p2p, "Not enough Query Response data");
                return;
        }
        end = pos + slen;
 
        if (comeback_delay) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented "
-                       "response - request fragments");
+               p2p_dbg(p2p, "Fragmented response - request fragments");
                if (p2p->sd_rx_resp) {
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
-                               "old SD reassembly buffer");
+                       p2p_dbg(p2p, "Drop old SD reassembly buffer");
                        wpabuf_free(p2p->sd_rx_resp);
                        p2p->sd_rx_resp = NULL;
                }
@@ -505,8 +524,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        if (pos + 4 > end)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+               p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
                return;
        }
        pos += 2;
@@ -514,21 +532,18 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        slen = WPA_GET_LE16(pos);
        pos += 2;
        if (pos + slen > end || slen < 3 + 1) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid ANQP Query Response length");
+               p2p_dbg(p2p, "Invalid ANQP Query Response length");
                return;
        }
 
        if (WPA_GET_BE24(pos) != OUI_WFA) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+               p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
                return;
        }
        pos += 3;
 
        if (*pos != P2P_OUI_TYPE) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
                return;
        }
        pos++;
@@ -536,8 +551,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        if (pos + 2 > end)
                return;
        update_indic = WPA_GET_LE16(pos);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Service Update Indicator: %u", update_indic);
+       p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
        pos += 2;
 
        p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
@@ -547,8 +561,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        if (p2p->sd_query) {
                if (!p2p->sd_query->for_all_peers) {
                        struct p2p_sd_query *q;
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Remove completed SD query %p",
+                       p2p_dbg(p2p, "Remove completed SD query %p",
                                p2p->sd_query);
                        q = p2p->sd_query;
                        p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -576,22 +589,20 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
        if (len < 1)
                return;
        dialog_token = *data;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dialog Token: %u",
-               dialog_token);
+       p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
        if (dialog_token != p2p->sd_resp_dialog_token) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-                       "response fragment for dialog token %u", dialog_token);
+               p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
+                       dialog_token);
                return;
        }
 
        if (p2p->sd_resp == NULL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-                       "response fragment available");
+               p2p_dbg(p2p, "No pending SD response fragment available");
                return;
        }
        if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-                       "response fragment for " MACSTR, MAC2STR(sa));
+               p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
+                       MAC2STR(sa));
                return;
        }
 
@@ -608,29 +619,29 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
                                           wpabuf_len(p2p->sd_resp));
        if (resp == NULL)
                return;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send GAS Comeback "
-               "Response (frag_id %d more=%d frag_len=%d)",
+       p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
                p2p->sd_frag_id, more, (int) frag_len);
        p2p->sd_frag_id++;
        p2p->sd_resp_pos += frag_len;
 
        if (more) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: %d more bytes "
-                       "remain to be sent",
+               p2p_dbg(p2p, "%d more bytes remain to be sent",
                        (int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
        } else {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: All fragments of "
-                       "SD response sent");
+               p2p_dbg(p2p, "All fragments of SD response sent");
                wpabuf_free(p2p->sd_resp);
                p2p->sd_resp = NULL;
        }
 
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
+       if (p2p_send_action(p2p, rx_freq, sa,
+#ifdef TIZEN_EXT
+                           p2p->cfg->own_addr, p2p->cfg->own_addr,
+#else
+                           p2p->cfg->dev_addr, p2p->cfg->dev_addr,
+#endif
                            wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Failed to send Action frame");
+               p2p_dbg(p2p, "Failed to send Action frame");
 
        wpabuf_free(resp);
 }
@@ -653,21 +664,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
 
        if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
            os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Ignore unexpected GAS Comeback Response from "
+               p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
                        MACSTR, MAC2STR(sa));
                return;
        }
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
        p2p_clear_timeout(p2p);
 
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Received GAS Comeback Response from " MACSTR " (len=%d)",
+       p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
                MAC2STR(sa), (int) len);
 
        if (len < 6 + 2) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Too short GAS Comeback Response frame");
+               p2p_dbg(p2p, "Too short GAS Comeback Response frame");
                return;
        }
 
@@ -680,22 +688,19 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        pos++;
        comeback_delay = WPA_GET_LE16(pos);
        pos += 2;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
+       p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
                "comeback_delay=%u",
                dialog_token, status_code, frag_id, more_frags,
                comeback_delay);
        /* TODO: check frag_id match */
        if (status_code) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Service Discovery failed: status code %u",
+               p2p_dbg(p2p, "Service Discovery failed: status code %u",
                        status_code);
                return;
        }
 
        if (*pos != WLAN_EID_ADV_PROTO) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unexpected IE in GAS Comeback Response: %u",
+               p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
                        *pos);
                return;
        }
@@ -704,15 +709,13 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        slen = *pos++;
        next = pos + slen;
        if (next > end || slen < 2) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid IE in GAS Comeback Response");
+               p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
                return;
        }
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported GAS advertisement protocol id %u",
+               p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
                        *pos);
                return;
        }
@@ -720,22 +723,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        pos = next;
        /* Query Response */
        if (pos + 2 > end) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
-                       "Response");
+               p2p_dbg(p2p, "Too short Query Response");
                return;
        }
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
-               slen);
+       p2p_dbg(p2p, "Query Response Length: %d", slen);
        if (pos + slen > end) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
-                       "Response data");
+               p2p_dbg(p2p, "Not enough Query Response data");
                return;
        }
        if (slen == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response "
-                       "data");
+               p2p_dbg(p2p, "No Query Response data");
                return;
        }
        end = pos + slen;
@@ -752,34 +751,29 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        if (pos + 4 > end)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+               p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
                return;
        }
        pos += 2;
 
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
-               "length: %u", slen);
+       p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
        if (slen < 3 + 1) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Invalid ANQP Query Response length");
+               p2p_dbg(p2p, "Invalid ANQP Query Response length");
                return;
        }
        if (pos + 4 > end)
                return;
 
        if (WPA_GET_BE24(pos) != OUI_WFA) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+               p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
                return;
        }
        pos += 3;
 
        if (*pos != P2P_OUI_TYPE) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Unsupported ANQP vendor type %u", *pos);
+               p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
                return;
        }
        pos++;
@@ -787,27 +781,23 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        if (pos + 2 > end)
                return;
        p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-               "P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic);
+       p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
        pos += 2;
 
 skip_nqp_header:
        if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
                return;
        wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly "
-               "buffer length: %u",
+       p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
                (unsigned int) wpabuf_len(p2p->sd_rx_resp));
 
        if (more_frags) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments "
-                       "remains");
+               p2p_dbg(p2p, "More fragments remains");
                /* TODO: what would be a good size limit? */
                if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
                        wpabuf_free(p2p->sd_rx_resp);
                        p2p->sd_rx_resp = NULL;
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long "
-                               "SD response - drop it");
+                       p2p_dbg(p2p, "Too long SD response - drop it");
                        return;
                }
                p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
@@ -821,8 +811,7 @@ skip_nqp_header:
        if (p2p->sd_query) {
                if (!p2p->sd_query->for_all_peers) {
                        struct p2p_sd_query *q;
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                               "P2P: Remove completed SD query %p",
+                       p2p_dbg(p2p, "Remove completed SD query %p",
                                p2p->sd_query);
                        q = p2p->sd_query;
                        p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -865,10 +854,29 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
 
        q->next = p2p->sd_queries;
        p2p->sd_queries = q;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
+       p2p_dbg(p2p, "Added SD Query %p", q);
+
+       if (dst == NULL) {
+               struct p2p_device *dev;
+               dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+                       dev->flags &= ~P2P_DEV_SD_INFO;
+       }
+
+       return q;
+}
 
+
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+                         const struct wpabuf *tlvs)
+{
+       struct p2p_sd_query *q;
+       q = p2p_sd_request(p2p, dst, tlvs);
+       if (q)
+               q->wsd = 1;
        return q;
 }
+#endif /* CONFIG_WIFI_DISPLAY */
 
 
 void p2p_sd_service_update(struct p2p_data *p2p)
@@ -880,8 +888,7 @@ void p2p_sd_service_update(struct p2p_data *p2p)
 int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
 {
        if (p2p_unlink_sd_query(p2p, req)) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Cancel pending SD query %p", req);
+               p2p_dbg(p2p, "Cancel pending SD query %p", req);
                p2p_free_sd_query(req);
                return 0;
        }
index da4b6ed..0da2682 100644 (file)
@@ -2,14 +2,8 @@
  * P2P - generic helper functions
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -52,11 +46,17 @@ int p2p_random(char *buf, size_t len)
 }
 
 
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
+/**
+ * p2p_channel_to_freq - Convert channel info to frequency
+ * @op_class: Operating class
+ * @channel: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int p2p_channel_to_freq(int op_class, int channel)
 {
-       /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
-       /* TODO: more regulatory classes */
-       switch (reg_class) {
+       /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+       /* TODO: more operating classes */
+       switch (op_class) {
        case 81:
                /* channels 1..13 */
                if (channel < 1 || channel > 13)
@@ -100,75 +100,34 @@ static int p2p_channel_to_freq_j4(int reg_class, int channel)
 
 
 /**
- * p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
- * @channel: Channel number
- * Returns: Frequency in MHz or -1 if the specified channel is unknown
- */
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
-{
-       if (country[2] == 0x04)
-               return p2p_channel_to_freq_j4(reg_class, channel);
-
-       /* These are mainly for backwards compatibility; to be removed */
-       switch (reg_class) {
-       case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
-               if (channel < 36 || channel > 48)
-                       return -1;
-               return 5000 + 5 * channel;
-       case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
-       case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
-               if (channel < 149 || channel > 161)
-                       return -1;
-               return 5000 + 5 * channel;
-       case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
-       case 12: /* US/12 = 2.407 GHz, channels 1..11 */
-       case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
-               if (channel < 1 || channel > 13)
-                       return -1;
-               return 2407 + 5 * channel;
-       case 31: /* JP/31 = 2.414 GHz, channel 14 */
-               if (channel != 14)
-                       return -1;
-               return 2414 + 5 * channel;
-       }
-
-       return -1;
-}
-
-
-/**
  * p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
  * @channel: Buffer for returning channel number
  * Returns: 0 on success, -1 if the specified frequency is unknown
  */
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-                       u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
 {
        /* TODO: more operating classes */
        if (freq >= 2412 && freq <= 2472) {
-               *reg_class = 81; /* 2.407 GHz, channels 1..13 */
+               *op_class = 81; /* 2.407 GHz, channels 1..13 */
                *channel = (freq - 2407) / 5;
                return 0;
        }
 
        if (freq == 2484) {
-               *reg_class = 82; /* channel 14 */
+               *op_class = 82; /* channel 14 */
                *channel = 14;
                return 0;
        }
 
        if (freq >= 5180 && freq <= 5240) {
-               *reg_class = 115; /* 5 GHz, channels 36..48 */
+               *op_class = 115; /* 5 GHz, channels 36..48 */
                *channel = (freq - 5000) / 5;
                return 0;
        }
 
        if (freq >= 5745 && freq <= 5805) {
-               *reg_class = 124; /* 5 GHz, channels 149..161 */
+               *op_class = 124; /* 5 GHz, channels 149..161 */
                *channel = (freq - 5000) / 5;
                return 0;
        }
@@ -260,12 +219,55 @@ int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
 }
 
 
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+                              unsigned int freq)
+{
+       size_t i, j;
+       for (i = 0; i < channels->reg_classes; i++) {
+               const struct p2p_reg_class *reg = &channels->reg_class[i];
+               for (j = 0; j < reg->channels; j++) {
+                       if (p2p_channel_to_freq(reg->reg_class,
+                                               reg->channel[j]) == (int) freq)
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
        u8 op_reg_class, op_channel;
-       if (p2p_freq_to_channel(p2p->cfg->country, freq,
-                               &op_reg_class, &op_channel) < 0)
+       if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
                return 0;
        return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
                                     op_channel);
 }
+
+
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+                              const struct p2p_channels *channels)
+{
+       unsigned int i;
+       int freq = 0;
+
+       if (channels == NULL) {
+               if (p2p->cfg->num_pref_chan) {
+                       freq = p2p_channel_to_freq(
+                               p2p->cfg->pref_chan[0].op_class,
+                               p2p->cfg->pref_chan[0].chan);
+                       if (freq < 0)
+                               freq = 0;
+               }
+               return freq;
+       }
+
+       for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+               freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
+                                          p2p->cfg->pref_chan[i].chan);
+               if (p2p_channels_includes_freq(channels, freq))
+                       return freq;
+       }
+
+       return 0;
+}
diff --git a/src/radius/.gitignore b/src/radius/.gitignore
new file mode 100644 (file)
index 0000000..a89a1f9
--- /dev/null
@@ -0,0 +1 @@
+libradius.a
index 3ead847..d1feec9 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -84,8 +78,8 @@ static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
 
 static int radius_msg_initialize(struct radius_msg *msg)
 {
-       msg->attr_pos =
-               os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
+       msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
+                                 sizeof(*msg->attr_pos));
        if (msg->attr_pos == NULL)
                return -1;
 
@@ -153,6 +147,12 @@ static const char *radius_code_string(u8 code)
        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?";
        }
 }
@@ -228,9 +228,10 @@ static struct radius_attr_type radius_attrs[] =
          RADIUS_ATTR_HEXDUMP },
        { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
          RADIUS_ATTR_INT32 },
-       { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+       { 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]))
 
@@ -268,7 +269,7 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
        printf("   Attribute %d (%s) length=%d\n",
               hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
 
-       if (attr == NULL)
+       if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
                return;
 
        len = hdr->length - sizeof(struct radius_attr_hdr);
@@ -331,7 +332,7 @@ void radius_msg_dump(struct radius_msg *msg)
 
        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));
+              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);
@@ -356,11 +357,11 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
                                   "Message-Authenticator");
                        return -1;
                }
-               msg->hdr->length = htons(wpabuf_len(msg->buf));
+               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 = htons(wpabuf_len(msg->buf));
+               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)",
@@ -386,7 +387,7 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
                printf("WARNING: Could not add Message-Authenticator\n");
                return -1;
        }
-       msg->hdr->length = htons(wpabuf_len(msg->buf));
+       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),
@@ -412,13 +413,52 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
 }
 
 
+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 = htons(wpabuf_len(msg->buf));
+       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);
@@ -433,6 +473,88 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
 }
 
 
+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)
 {
@@ -440,8 +562,8 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
                size_t *nattr_pos;
                int nlen = msg->attr_size * 2;
 
-               nattr_pos = os_realloc(msg->attr_pos,
-                                      nlen * sizeof(*msg->attr_pos));
+               nattr_pos = os_realloc_array(msg->attr_pos, nlen,
+                                            sizeof(*msg->attr_pos));
                if (nattr_pos == NULL)
                        return -1;
 
@@ -511,7 +633,7 @@ struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
 
        hdr = (struct radius_hdr *) data;
 
-       msg_len = ntohs(hdr->length);
+       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;
@@ -585,9 +707,9 @@ 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 *eap_len)
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
 {
-       u8 *eap, *pos;
+       struct wpabuf *eap;
        size_t len, i;
        struct radius_attr_hdr *attr;
 
@@ -597,30 +719,27 @@ u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
        len = 0;
        for (i = 0; i < msg->attr_used; i++) {
                attr = radius_get_attr_hdr(msg, i);
-               if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
+               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 = os_malloc(len);
+       eap = wpabuf_alloc(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) {
+               if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+                   attr->length > sizeof(struct radius_attr_hdr)) {
                        int flen = attr->length - sizeof(*attr);
-                       os_memcpy(pos, attr + 1, flen);
-                       pos += flen;
+                       wpabuf_put_data(eap, attr + 1, flen);
                }
        }
 
-       if (eap_len)
-               *eap_len = len;
-
        return eap;
 }
 
@@ -721,7 +840,7 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
 
        for (i = 0; i < src->attr_used; i++) {
                attr = radius_get_attr_hdr(src, i);
-               if (attr->type == type) {
+               if (attr->type == type && attr->length >= sizeof(*attr)) {
                        if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
                                                 attr->length - sizeof(*attr)))
                                return -1;
@@ -778,7 +897,8 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
                u32 vendor_id;
                struct radius_attr_vendor *vhdr;
 
-               if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+               if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
+                   attr->length < sizeof(*attr))
                        continue;
 
                left = attr->length - sizeof(*attr);
@@ -1151,7 +1271,7 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
                }
        }
 
-       if (!attr)
+       if (!attr || attr->length < sizeof(*attr))
                return -1;
 
        dlen = attr->length - sizeof(*attr);
@@ -1176,7 +1296,7 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
                }
        }
 
-       if (!attr)
+       if (!attr || attr->length < sizeof(*attr))
                return -1;
 
        *buf = (u8 *) (attr + 1);
@@ -1227,6 +1347,8 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
 
        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)
@@ -1284,11 +1406,12 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
  * @secret: RADIUS shared secret
  * @secret_len: Length of secret
  * @sent_msg: Sent RADIUS message
- * Returns: pointer to password (free with os_free) or %NULL
+ * @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)
+                                     struct radius_msg *sent_msg, size_t n)
 {
        u8 *buf = NULL;
        size_t buflen;
@@ -1298,7 +1421,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
        size_t len[3];
        u8 hash[16];
        u8 *pos;
-       size_t i;
+       size_t i, j = 0;
        struct radius_attr_hdr *attr;
        const u8 *data;
        size_t dlen;
@@ -1306,7 +1429,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
        size_t fdlen = -1;
        char *ret = NULL;
 
-       /* find attribute with lowest tag and check it */
+       /* 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 ||
@@ -1319,11 +1442,13 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
                dlen = attr->length - sizeof(*attr);
                if (dlen <= 3 || dlen % 16 != 3)
                        continue;
-               if (fdata != NULL && fdata[0] <= data[0])
+               j++;
+               if (j <= n)
                        continue;
 
                fdata = data;
                fdlen = dlen;
+               break;
        }
        if (fdata == NULL)
                goto out;
@@ -1412,7 +1537,7 @@ int radius_copy_class(struct radius_class_data *dst,
        if (src->attr == NULL)
                return 0;
 
-       dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+       dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
        if (dst->attr == NULL)
                return -1;
 
@@ -1430,3 +1555,24 @@ int radius_copy_class(struct radius_class_data *dst,
 
        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;
+}
index e69a047..2031054 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RADIUS_H
@@ -24,7 +18,7 @@
 struct radius_hdr {
        u8 code;
        u8 identifier;
-       u16 length; /* including this header */
+       be16 length; /* including this header */
        u8 authenticator[16];
        /* followed by length-20 octets of attributes */
 } STRUCT_PACKED;
@@ -37,6 +31,12 @@ enum { RADIUS_CODE_ACCESS_REQUEST = 1,
        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
 };
 
@@ -89,7 +89,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        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_NAS_IPV6_ADDRESS = 95,
+       RADIUS_ATTR_ERROR_CAUSE = 101
 };
 
 
@@ -198,14 +199,21 @@ 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);
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *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);
@@ -234,7 +242,7 @@ 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);
+                                     struct radius_msg *sent_msg, size_t n);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
                                            u32 value)
@@ -274,4 +282,6 @@ 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 */
index 691f77a..425ad93 100644 (file)
@@ -2,14 +2,8 @@
  * RADIUS client
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -287,8 +281,8 @@ int radius_client_register(struct radius_client_data *radius,
                num = &radius->num_auth_handlers;
        }
 
-       newh = os_realloc(*handlers,
-                         (*num + 1) * sizeof(struct radius_rx_handler));
+       newh = os_realloc_array(*handlers, *num + 1,
+                               sizeof(struct radius_rx_handler));
        if (newh == NULL)
                return -1;
 
@@ -511,7 +505,7 @@ static void radius_client_update_timeout(struct radius_client_data *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));
+                      " %ld seconds", (long int) (first - now.sec));
 }
 
 
@@ -684,7 +678,7 @@ int radius_client_send(struct radius_client_data *radius,
        radius_client_list_add(radius, msg, msg_type, shared_secret,
                               shared_secret_len, addr);
 
-       return res;
+       return 0;
 }
 
 
index 18e7290..3db16aa 100644 (file)
@@ -2,14 +2,8 @@
  * RADIUS client
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RADIUS_CLIENT_H
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
new file mode 100644 (file)
index 0000000..bded965
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <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);
+}
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
new file mode 100644 (file)
index 0000000..738b18b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS)
+ * Copyright (c) 2012, Jouni Malinen <j@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 */
index 47948bc..5b2d711 100644 (file)
@@ -2,14 +2,8 @@
  * RADIUS authentication server
  * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -695,8 +689,7 @@ static int radius_server_request(struct radius_server_data *data,
                                 const char *from_addr, int from_port,
                                 struct radius_session *force_sess)
 {
-       u8 *eap = NULL;
-       size_t eap_len;
+       struct wpabuf *eap = NULL;
        int res, state_included = 0;
        u8 statebuf[4];
        unsigned int state;
@@ -760,7 +753,7 @@ static int radius_server_request(struct radius_server_data *data,
                return -1;
        }
                      
-       eap = radius_msg_get_eap(msg, &eap_len);
+       eap = radius_msg_get_eap(msg);
        if (eap == NULL) {
                RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
                             from_addr);
@@ -769,7 +762,7 @@ static int radius_server_request(struct radius_server_data *data,
                return -1;
        }
 
-       RADIUS_DUMP("Received EAP data", eap, eap_len);
+       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.
@@ -779,10 +772,7 @@ static int radius_server_request(struct radius_server_data *data,
         * 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->eapRespData = eap;
        sess->eap_if->eapResp = TRUE;
        eap_server_sm_step(sess->eap);
 
index 8d6e2ab..82466c3 100644 (file)
@@ -2,14 +2,8 @@
  * RADIUS authentication server
  * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RADIUS_SERVER_H
index 2b3332e..789ac25 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
  * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -223,20 +217,17 @@ static int wpa_supplicant_process_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 {
+       cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+                                         sm->allowed_pairwise_cipher, 0);
+       if (cipher < 0) {
                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;
        }
+       wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+                  wpa_cipher_txt(cipher));
 
        /* 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
@@ -273,10 +264,7 @@ static int wpa_supplicant_process_smk_m2(
        /* 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);
+       RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
        pos += RSN_SELECTOR_LEN;
 
        hdr->len = (pos - peerkey->rsnie_p) - 2;
@@ -350,7 +338,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
 
        msg->type = EAPOL_KEY_TYPE_RSN;
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -358,7 +346,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
        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)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                WPA_PUT_BE16(msg->key_length, 16);
        else
                WPA_PUT_BE16(msg->key_length, 32);
@@ -409,7 +397,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
 
        msg->type = EAPOL_KEY_TYPE_RSN;
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -418,7 +406,7 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
                WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
        WPA_PUT_BE16(msg->key_info, key_info);
 
-       if (peerkey->cipher == WPA_CIPHER_CCMP)
+       if (peerkey->cipher != WPA_CIPHER_TKIP)
                WPA_PUT_BE16(msg->key_length, 16);
        else
                WPA_PUT_BE16(msg->key_length, 32);
@@ -502,14 +490,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
        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 {
+       cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+                                         sm->allowed_pairwise_cipher, 0);
+       if (cipher < 0) {
                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,
@@ -518,6 +501,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
                /* TODO: abort negotiation */
                return -1;
        }
+       wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+                  wpa_cipher_txt(cipher));
+       peerkey->cipher = cipher;
 
        return 0;
 }
@@ -1022,7 +1008,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
                return -1;
        }
 
-       if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+       if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
                ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1061,17 +1047,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
        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++;
-       }
+       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;
index 2613127..b8845f7 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
  * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PEERKEY_H
index 3877efb..33fa1a2 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -21,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 static const int pmksa_cache_max_entries = 32;
 
@@ -31,7 +25,7 @@ struct rsn_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);
+                       enum pmksa_free_reason reason);
        void *ctx;
 };
 
@@ -47,11 +41,11 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 
 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
                                   struct rsn_pmksa_cache_entry *entry,
-                                  int replace)
+                                  enum pmksa_free_reason reason)
 {
        wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
        pmksa->pmksa_count--;
-       pmksa->free_cb(entry, pmksa->ctx, replace);
+       pmksa->free_cb(entry, pmksa->ctx, reason);
        _pmksa_cache_free_entry(entry);
 }
 
@@ -67,7 +61,7 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
                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_free_entry(pmksa, entry, PMKSA_EXPIRE);
        }
 
        pmksa_cache_set_expiration(pmksa);
@@ -99,7 +93,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
        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);
+               pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
        if (entry) {
                sec = pmksa->pmksa->reauth_time - now.sec;
                if (sec < 0)
@@ -170,30 +164,23 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                                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);
 
                        /*
                         * 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.
+                        * the new PMK. Only clear other entries if they have a
+                        * matching PMK and this PMK has been used successfully
+                        * with the current AP, i.e., if opportunistic flag has
+                        * been cleared in wpa_supplicant_key_neg_complete().
                         */
-                       pmksa_cache_flush(pmksa, network_ctx);
+                       wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+                                  "the current AP and any PMKSA cache entry "
+                                  "that was based on the old PMK");
+                       if (!pos->opportunistic)
+                               pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+                                                 pos->pmk_len);
+                       pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
                        break;
                }
                prev = pos;
@@ -203,11 +190,25 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
        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));
-               pmksa_cache_free_entry(pmksa, pos, 0);
+
+               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 */
@@ -228,8 +229,8 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                prev->next = entry;
        }
        pmksa->pmksa_count++;
-       wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
-                  MAC2STR(entry->aa));
+       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;
@@ -240,15 +241,22 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
  * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
  */
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+                      const u8 *pmk, size_t pmk_len)
 {
        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) {
+               if ((entry->network_ctx == network_ctx ||
+                    network_ctx == NULL) &&
+                   (pmk == NULL ||
+                    (pmk_len == entry->pmk_len &&
+                     os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
                        wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
                                   "for " MACSTR, MAC2STR(entry->aa));
                        if (prev)
@@ -257,7 +265,7 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
                                pmksa->pmksa = entry->next;
                        tmp = entry;
                        entry = entry->next;
-                       pmksa_cache_free_entry(pmksa, tmp, 0);
+                       pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
                        removed++;
                } else {
                        prev = entry;
@@ -297,16 +305,19 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
  * @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 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))
+                    os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+                   (network_ctx == NULL || network_ctx == entry->network_ctx))
                        return entry;
                entry = entry->next;
        }
@@ -410,20 +421,32 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
                            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);
+               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);
+               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: PMKID",
+               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;
 }
 
@@ -484,7 +507,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
  */
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                void *ctx, enum pmksa_free_reason reason),
                 void *ctx, struct wpa_sm *sm)
 {
        struct rsn_pmksa_cache *pmksa;
@@ -499,4 +522,4 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
        return pmksa;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
index 840827d..6cbf89a 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant - WPA2/RSN PMKSA cache functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PMKSA_CACHE_H
@@ -44,15 +38,22 @@ struct rsn_pmksa_cache_entry {
 
 struct rsn_pmksa_cache;
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+enum pmksa_free_reason {
+       PMKSA_FREE,
+       PMKSA_REPLACE,
+       PMKSA_EXPIRE,
+};
+
+#ifdef IEEE8021X_EAPOL
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                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 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,
@@ -65,13 +66,14 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 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);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+                      const u8 *pmk, size_t pmk_len);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                void *ctx, enum pmksa_free_reason reason),
                 void *ctx, struct wpa_sm *sm)
 {
        return (void *) -1;
@@ -82,7 +84,8 @@ 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)
+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
+               const void *network_ctx)
 {
        return NULL;
 }
@@ -119,10 +122,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 }
 
 static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
-                                    void *network_ctx)
+                                    void *network_ctx,
+                                    const u8 *pmk, size_t pmk_len)
 {
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PMKSA_CACHE_H */
index fefca83..c51620e 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -24,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -311,7 +305,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
        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);
+               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 "
@@ -458,7 +452,7 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
        if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
                return;
 
-       pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL);
+       pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
        if (pmksa && (!pmksa->opportunistic ||
                      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
                return;
@@ -514,4 +508,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
        return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
index f8240ab..277f066 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - WPA2/RSN pre-authentication functions
  * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PREAUTH_H
@@ -17,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -33,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
                           int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -80,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
        return 0;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PREAUTH_H */
index 27090e3..539aa25 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - TDLS
  * Copyright (c) 2010-2011, 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -43,8 +37,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 TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
 
 #define TDLS_MIC_LEN           16
 
@@ -92,6 +88,7 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
 
 struct wpa_tdls_peer {
        struct wpa_tdls_peer *next;
+       unsigned int reconfig_key:1;
        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 */
@@ -126,6 +123,16 @@ struct wpa_tdls_peer {
 
        u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
        size_t supp_rates_len;
+
+       struct ieee80211_ht_capabilities *ht_capabilities;
+       struct ieee80211_vht_capabilities *vht_capabilities;
+
+       u8 qos_info;
+
+       u16 aid;
+
+       u8 *ext_capab;
+       size_t ext_capab_len;
 };
 
 
@@ -239,8 +246,13 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
 
        eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 
-       peer->sm_tmr.count = TPK_RETRY_COUNT;
-       peer->sm_tmr.timer = TPK_TIMEOUT;
+       if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+               peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+               peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+       } else {
+               peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+               peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+       }
 
        /* Copy message to resend on timeout */
        os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
@@ -256,7 +268,8 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
 
        wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
                   "(action_code=%u)", action_code);
-       eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+       eloop_register_timeout(peer->sm_tmr.timer / 1000,
+                              (peer->sm_tmr.timer % 1000) * 1000,
                               wpa_tdls_tpk_retry_timeout, sm, peer);
        return 0;
 }
@@ -291,7 +304,6 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *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)",
@@ -318,7 +330,8 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
                }
 
                eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
-               eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+               eloop_register_timeout(peer->sm_tmr.timer / 1000,
+                                      (peer->sm_tmr.timer % 1000) * 1000,
                                       wpa_tdls_tpk_retry_timeout, sm, peer);
        } else {
                eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
@@ -614,9 +627,16 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
                   MAC2STR(peer->addr));
        eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
        eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+       peer->reconfig_key = 0;
        peer->initiator = 0;
        os_free(peer->sm_tmr.buf);
        peer->sm_tmr.buf = NULL;
+       os_free(peer->ht_capabilities);
+       peer->ht_capabilities = NULL;
+       os_free(peer->vht_capabilities);
+       peer->vht_capabilities = NULL;
+       os_free(peer->ext_capab);
+       peer->ext_capab = NULL;
        peer->rsnie_i_len = peer->rsnie_p_len = 0;
        peer->cipher = 0;
        peer->tpk_set = peer->tpk_success = 0;
@@ -721,8 +741,7 @@ skip_ies:
 
        /* 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);
+                         reason_code, rbuf, pos - rbuf);
        os_free(rbuf);
 
        /* clear the Peerkey statemachine */
@@ -874,10 +893,20 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
 
 
 static struct wpa_tdls_peer *
-wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
 {
        struct wpa_tdls_peer *peer;
 
+       if (existing)
+               *existing = 0;
+       for (peer = sm->tdls; peer; peer = peer->next) {
+               if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) {
+                       if (existing)
+                               *existing = 1;
+                       return peer; /* re-use existing entry */
+               }
+       }
+
        wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
                   MAC2STR(addr));
 
@@ -1288,7 +1317,7 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
                return -1;
        }
 
-       peer = wpa_tdls_add_peer(sm, addr);
+       peer = wpa_tdls_add_peer(sm, addr, NULL);
        if (peer == NULL)
                return -1;
 
@@ -1315,21 +1344,91 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
                wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
                return -1;
        }
+       peer->supp_rates_len = merge_byte_arrays(
+               peer->supp_rates, sizeof(peer->supp_rates),
+               kde->supp_rates + 2, kde->supp_rates_len - 2,
+               kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+               kde->ext_supp_rates_len - 2);
+       return 0;
+}
 
-       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;
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+                             struct wpa_tdls_peer *peer)
+{
+       if (!kde->ht_capabilities ||
+           kde->ht_capabilities_len <
+           sizeof(struct ieee80211_ht_capabilities) ) {
+               wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+                          "received");
+               return 0;
+       }
+
+       if (!peer->ht_capabilities) {
+               peer->ht_capabilities =
+                        os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+               if (peer->ht_capabilities == NULL)
+                        return -1;
        }
 
+       os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+                  sizeof(struct ieee80211_ht_capabilities));
+       wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+                   (u8 *) peer->ht_capabilities,
+                   sizeof(struct ieee80211_ht_capabilities));
+
+       return 0;
+}
+
+
+static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
+                             struct wpa_tdls_peer *peer)
+{
+       if (!kde->vht_capabilities ||
+           kde->vht_capabilities_len <
+           sizeof(struct ieee80211_vht_capabilities) ) {
+               wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities "
+                          "received");
+               return 0;
+       }
+
+       if (!peer->vht_capabilities) {
+               peer->vht_capabilities =
+                        os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+               if (peer->vht_capabilities == NULL)
+                        return -1;
+       }
+
+       os_memcpy(peer->vht_capabilities, kde->vht_capabilities,
+                  sizeof(struct ieee80211_vht_capabilities));
+       wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities",
+                   (u8 *) peer->vht_capabilities,
+                   sizeof(struct ieee80211_vht_capabilities));
+
+       return 0;
+}
+
+
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+                              struct wpa_tdls_peer *peer)
+{
+       if (!kde->ext_capab) {
+               wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+                          "received");
+               return 0;
+       }
+
+       if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+               /* Need to allocate buffer to fit the new information */
+               os_free(peer->ext_capab);
+               peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+               if (peer->ext_capab == NULL)
+                       return -1;
+       }
+
+       peer->ext_capab_len = kde->ext_capab_len - 2;
+       os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
        return 0;
 }
 
@@ -1369,17 +1468,59 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 
        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;
+       peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer);
+       if (peer == NULL)
+               goto error;
+
+       /* 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);
                }
-       }
 
-       if (peer == NULL) {
-               peer = wpa_tdls_add_peer(sm, src_addr);
-               if (peer == NULL)
-                       goto error;
+               /*
+                * 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));
+                               if (sm->tdls_external_setup)
+                                       wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+                                                        src_addr);
+                               else
+                                       wpa_tdls_del_key(sm, peer);
+                               wpa_tdls_peer_free(sm, peer);
+                       }
+               }
        }
 
        /* capability information */
@@ -1412,17 +1553,24 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
        if (copy_supp_rates(&kde, peer) < 0)
                goto error;
 
+       if (copy_peer_ht_capab(&kde, peer) < 0)
+               goto error;
+
+       if (copy_peer_vht_capab(&kde, peer) < 0)
+               goto error;
+
+       if (copy_peer_ext_capab(&kde, peer) < 0)
+               goto error;
+
+       peer->qos_info = kde.qosinfo;
+
+       peer->aid = kde.aid;
+
 #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;
-               }
+               peer = wpa_tdls_add_peer(sm, src_addr, NULL);
+               if (peer == NULL)
+                       goto error;
                wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
                           "TDLS setup - send own request");
                peer->initiator = 1;
@@ -1508,52 +1656,6 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
        }
 
 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) {
@@ -1641,7 +1743,8 @@ skip_rsn:
 
 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_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 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) {
@@ -1658,7 +1761,7 @@ error:
 }
 
 
-static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static int 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);
@@ -1681,11 +1784,24 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *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);
+       /* add supported rates, capabilities, and qos_info to the TDLS peer */
+       if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
+                                   peer->capability,
+                                   peer->supp_rates, peer->supp_rates_len,
+                                   peer->ht_capabilities,
+                                   peer->vht_capabilities,
+                                   peer->qos_info, peer->ext_capab,
+                                   peer->ext_capab_len) < 0)
+               return -1;
 
-       wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+       if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
+               wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
+                          "driver");
+               return -1;
+       }
+       peer->reconfig_key = 0;
+
+       return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
 
 
@@ -1704,6 +1820,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
        int ielen;
        u16 status;
        const u8 *pos;
+       int ret;
 
        wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
                   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1716,6 +1833,16 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
                           "TPK M2: " MACSTR, MAC2STR(src_addr));
                return -1;
        }
+       if (!peer->initiator) {
+               /*
+                * This may happen if both devices try to initiate TDLS at the
+                * same time and we accept the TPK M1 from the peer in
+                * wpa_tdls_process_tpk_m1() and clear our previous state.
+                */
+               wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so "
+                          "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
+               return -1;
+       }
        wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
 
        if (len < 3 + 2 + 1)
@@ -1779,6 +1906,19 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
        if (copy_supp_rates(&kde, peer) < 0)
                goto error;
 
+       if (copy_peer_ht_capab(&kde, peer) < 0)
+               goto error;
+
+       if (copy_peer_vht_capab(&kde, peer) < 0)
+               goto error;
+
+       if (copy_peer_ext_capab(&kde, peer) < 0)
+               goto error;
+
+       peer->qos_info = kde.qosinfo;
+
+       peer->aid = kde.aid;
+
        if (!wpa_tdls_get_privacy(sm)) {
                peer->rsnie_p_len = 0;
                peer->cipher = WPA_CIPHER_NONE;
@@ -1875,7 +2015,15 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
                return -1;
        }
 
-       wpa_tdls_set_key(sm, peer);
+       if (wpa_tdls_set_key(sm, peer) < 0) {
+               /*
+                * Some drivers may not be able to config the key prior to full
+                * STA entry having been configured.
+                */
+               wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+                          "STA entry is complete");
+               peer->reconfig_key = 1;
+       }
 
 skip_rsn:
        peer->dtoken = dtoken;
@@ -1884,9 +2032,13 @@ skip_rsn:
                   "TPK Handshake Message 3");
        wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
 
-       wpa_tdls_enable_link(sm, peer);
-
-       return 0;
+       ret = wpa_tdls_enable_link(sm, peer);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+               wpa_tdls_do_teardown(sm, peer,
+                                    WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+       }
+       return ret;
 
 error:
        wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
@@ -1909,6 +2061,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
        u16 status;
        const u8 *pos;
        u32 lifetime;
+       int ret;
 
        wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
                   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -2019,13 +2172,24 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
                return -1;
        }
 
-       if (wpa_tdls_set_key(sm, peer) < 0)
-               return -1;
+       if (wpa_tdls_set_key(sm, peer) < 0) {
+               /*
+                * Some drivers may not be able to config the key prior to full
+                * STA entry having been configured.
+                */
+               wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+                          "STA entry is complete");
+               peer->reconfig_key = 1;
+       }
 
 skip_rsn:
-       wpa_tdls_enable_link(sm, peer);
-
-       return 0;
+       ret = wpa_tdls_enable_link(sm, peer);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+               wpa_tdls_do_teardown(sm, peer,
+                                    WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+       }
+       return ret;
 }
 
 
@@ -2075,23 +2239,15 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
                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 = wpa_tdls_add_peer(sm, addr, NULL);
+       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);
+       wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
+                               NULL, 0);
 
        if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
                wpa_tdls_disable_link(sm, peer->addr);
@@ -2102,12 +2258,12 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
 }
 
 
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr)
 {
        struct wpa_tdls_peer *peer;
 
        if (sm->tdls_disabled || !sm->tdls_supported)
-               return -1;
+               return;
 
        for (peer = sm->tdls; peer; peer = peer->next) {
                if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
@@ -2115,7 +2271,7 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
        }
 
        if (peer == NULL || !peer->tpk_success)
-               return -1;
+               return;
 
        if (sm->tdls_external_setup) {
                /*
@@ -2124,8 +2280,6 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
                 */
                wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
        }
-
-       return wpa_tdls_start(sm, addr);
 }
 
 
@@ -2208,7 +2362,9 @@ int wpa_tdls_init(struct wpa_sm *sm)
        if (sm == NULL)
                return -1;
 
-       sm->l2_tdls = l2_packet_init(sm->ifname, sm->own_addr,
+       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) {
@@ -2236,6 +2392,28 @@ int wpa_tdls_init(struct wpa_sm *sm)
 }
 
 
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+       struct wpa_tdls_peer *peer;
+
+       peer = sm->tdls;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+       while (peer) {
+               wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+                          MAC2STR(peer->addr));
+               if (sm->tdls_external_setup)
+                       wpa_tdls_send_teardown(sm, peer->addr,
+                                              WLAN_REASON_DEAUTH_LEAVING);
+               else
+                       wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+               peer = peer->next;
+       }
+}
+
+
 static void wpa_tdls_remove_peers(struct wpa_sm *sm)
 {
        struct wpa_tdls_peer *peer, *tmp;
index f35f9ee..292255c 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -97,7 +91,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 
        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)
+       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;
@@ -151,7 +145,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                 * 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);
+               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");
@@ -195,22 +190,29 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 #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)) {
-                               pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len,
-                                               src_addr, sm->own_addr,
-                                               sm->network_ctx, 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)) {
+                           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 "
@@ -354,7 +356,7 @@ 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;
+       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);
@@ -390,7 +392,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 
        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);
@@ -403,7 +404,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                                    "Authenticator", ie.pmkid, PMKID_LEN);
                }
        }
-#endif /* CONFIG_NO_WPA2 */
 
        res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
        if (res == -2) {
@@ -518,28 +518,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
        wpa_dbg(sm->ctx->msg_ctx, 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:
+       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;
-       default:
+       }
+
+       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 {
@@ -572,55 +567,25 @@ static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
                                             int *key_rsc_len,
                                             enum wpa_alg *alg)
 {
-       int ret = 0;
+       int klen;
 
-       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:
+       *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);
 
-       if (ret < 0 ) {
+       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 ret;
+       return 0;
 }
 
 
@@ -697,7 +662,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
                                       const u8 *gtk, size_t gtk_len,
                                       int key_info)
 {
-#ifndef CONFIG_NO_WPA2
        struct wpa_gtk_data gd;
 
        /*
@@ -736,9 +700,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        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 */
 }
 
 
@@ -816,7 +777,7 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm,
                            rsn_ie, rsn_ie_len);
        }
 
-       wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+       wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
 }
 
 
@@ -1120,23 +1081,12 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        }
 
        keylen = WPA_GET_BE16(key->key_length);
-       switch (sm->pairwise_cipher) {
-       case WPA_CIPHER_CCMP:
-               if (keylen != 16) {
-                       wpa_msg(sm->ctx->msg_ctx, 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_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: Invalid TKIP key length %d (src=" MACSTR
-                               ")", keylen, MAC2STR(sm->bssid));
-                       goto failed;
-               }
-               break;
+       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,
@@ -1716,6 +1666,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                } 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) {
@@ -1850,23 +1807,6 @@ out:
 
 
 #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) {
@@ -1890,6 +1830,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
        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:
@@ -1898,30 +1842,6 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
 }
 
 
-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
@@ -1969,7 +1889,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
                          rsna ? "TRUE" : "FALSE",
                          rsna ? "TRUE" : "FALSE",
                          RSN_VERSION,
-                         wpa_cipher_bits(sm->group_cipher),
+                         wpa_cipher_key_len(sm->group_cipher) * 8,
                          sm->dot11RSNAConfigPMKLifetime,
                          sm->dot11RSNAConfigPMKReauthThreshold,
                          sm->dot11RSNAConfigSATimeout);
@@ -1989,12 +1909,16 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
                "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)),
+               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_suite(sm, sm->pairwise_cipher)),
-               RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+               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;
@@ -2005,25 +1929,40 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
 
 
 static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace)
+                                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 (sm->cur_pmksa == entry ||
+               /*
+                * 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: 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;
-               }
+                       "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);
        }
@@ -2154,6 +2093,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
 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
@@ -2446,10 +2386,41 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
        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;
 }
 
 
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+       struct wpa_ie_data rsn;
+
+       if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+               return 0;
+
+       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))
+               return 1;
+
+       return 0;
+}
+
+
 /**
  * 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()
@@ -2624,11 +2595,7 @@ 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)
 {
-#ifndef CONFIG_NO_WPA2
        return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2659,7 +2626,80 @@ 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)
 {
-#ifndef CONFIG_NO_WPA2
-       pmksa_cache_flush(sm->pmksa, network_ctx);
-#endif /* CONFIG_NO_WPA2 */
+       pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
+}
+
+
+#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 */
index 4c1750f..26e9c6c 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - WPA definitions
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_H
@@ -18,6 +12,7 @@
 #include "common/defs.h"
 #include "common/eapol_common.h"
 #include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
 
 struct wpa_sm;
 struct eapol_sm;
@@ -30,7 +25,6 @@ struct wpa_sm_ctx {
        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,
@@ -62,9 +56,13 @@ struct wpa_sm_ctx {
                              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,
+       int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
                                u16 capability, const u8 *supp_rates,
-                               size_t supp_rates_len);
+                               size_t supp_rates_len,
+                               const struct ieee80211_ht_capabilities *ht_capab,
+                               const struct ieee80211_vht_capabilities *vht_capab,
+                               u8 qosinfo, const u8 *ext_capab,
+                               size_t ext_capab_len);
 #endif /* CONFIG_TDLS */
        void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
                                  const u8 *replay_ctr);
@@ -125,6 +123,7 @@ unsigned int wpa_sm_get_param(struct wpa_sm *sm,
 
 int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
                      int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
 
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
 
@@ -246,6 +245,11 @@ static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
        return 0;
 }
 
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+       return 0;
+}
+
 static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
                                      int pairwise)
 {
@@ -317,6 +321,7 @@ 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);
+void wpa_reset_ft_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,
@@ -348,6 +353,10 @@ static inline int wpa_ft_is_completed(struct wpa_sm *sm)
        return 0;
 }
 
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
 static inline int
 wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
                             const u8 *src_addr)
@@ -362,14 +371,17 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 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);
+void wpa_tdls_remove(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_teardown_peers(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 */
index dbf5996..3a40c96 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -177,16 +171,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
        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 {
+       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 */
@@ -194,16 +188,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
        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 {
+       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 */
@@ -329,21 +321,15 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 
        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:
+       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");
@@ -489,7 +475,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
                    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 
        bssid = target_ap;
-       ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+       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);
@@ -548,6 +534,13 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
 }
 
 
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+       if (sm != NULL)
+               sm->ft_completed = 0;
+}
+
+
 static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
                                      size_t gtk_elem_len)
 {
@@ -577,28 +570,10 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
                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:
+       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;
@@ -621,6 +596,13 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
        }
 
        wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+       if (sm->group_cipher == WPA_CIPHER_TKIP) {
+               /* Swap Tx/Rx keys for Michael MIC */
+               u8 tmp[8];
+               os_memcpy(tmp, gtk + 16, 8);
+               os_memcpy(gtk + 16, gtk + 24, 8);
+               os_memcpy(gtk + 24, tmp, 8);
+       }
        if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
                           gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
                wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
@@ -820,9 +802,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
        if (parse.ric) {
                wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
                            parse.ric, parse.ric_len);
-               /* TODO: parse response and inform driver about results */
+               /* TODO: parse response and inform driver about results when
+                * using wpa_supplicant SME */
        }
 
+       wpa_printf(MSG_DEBUG, "FT: Completed successfully");
+
        return 0;
 }
 
index 39124c4..0e0d373 100644 (file)
@@ -2,14 +2,8 @@
  * Internal WPA/RSN supplicant state machine definitions
  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_I_H
@@ -149,12 +143,6 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
        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,
@@ -294,13 +282,18 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
 
 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)
+                       u16 aid, u16 capability, const u8 *supp_rates,
+                       size_t supp_rates_len,
+                       const struct ieee80211_ht_capabilities *ht_capab,
+                       const struct ieee80211_vht_capabilities *vht_capab,
+                       u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
 {
        if (sm->ctx->tdls_peer_addset)
                return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
-                                                capability, supp_rates,
-                                                supp_rates_len);
+                                                aid, capability, supp_rates,
+                                                supp_rates_len, ht_capab,
+                                                vht_capab, qosinfo,
+                                                ext_capab, ext_capab_len);
        return -1;
 }
 #endif /* CONFIG_TDLS */
index cbbc54f..50b9272 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - WPA/RSN IE and KDE processing
  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -47,6 +41,7 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
 {
        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)
@@ -58,34 +53,26 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
        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 {
+       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;
-       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 {
+       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;
@@ -96,6 +83,8 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
                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);
@@ -118,10 +107,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                              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 +
@@ -136,34 +125,26 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        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 {
+       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;
-       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 {
+       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;
@@ -172,6 +153,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                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);
@@ -184,6 +167,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        } 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);
@@ -230,9 +219,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
 
        return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -437,6 +423,17 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
                        ie->ext_supp_rates = pos;
                        ie->ext_supp_rates_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_HT_CAP) {
+                       ie->ht_capabilities = pos + 2;
+                       ie->ht_capabilities_len = pos[1];
+               } else if (*pos == WLAN_EID_VHT_AID) {
+                       if (pos[1] >= 2)
+                               ie->aid = WPA_GET_LE16(pos + 2);
+               } else if (*pos == WLAN_EID_VHT_CAP) {
+                       ie->vht_capabilities = pos + 2;
+                       ie->vht_capabilities_len = pos[1];
+               } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+                       ie->qosinfo = pos[2];
                } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
                        ret = wpa_parse_generic(pos, end, ie);
                        if (ret < 0)
index c13d94c..2c78801 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - WPA/RSN IE and KDE definitions
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_IE_H
@@ -55,6 +49,12 @@ struct wpa_eapol_ie_parse {
        size_t supp_rates_len;
        const u8 *ext_supp_rates;
        size_t ext_supp_rates_len;
+       const u8 *ht_capabilities;
+       size_t ht_capabilities_len;
+       const u8 *vht_capabilities;
+       size_t vht_capabilities_len;
+       u8 qosinfo;
+       u16 aid;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/.gitignore b/src/tls/.gitignore
new file mode 100644 (file)
index 0000000..d43242d
--- /dev/null
@@ -0,0 +1 @@
+libtls.a
index 3391245..53acd53 100644 (file)
@@ -2,14 +2,8 @@
  * ASN.1 DER parsing
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 2ff571e..6342c4c 100644 (file)
@@ -2,14 +2,8 @@
  * ASN.1 DER parsing
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef ASN1_H
index 5c0fc62..f3baafe 100644 (file)
@@ -2,14 +2,8 @@
  * Big number math
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f25e267..24acdce 100644 (file)
@@ -2,14 +2,8 @@
  * Big number math
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BIGNUM_H
index 7c9857f..3fb8fbe 100644 (file)
@@ -42,6 +42,9 @@
 /* Include faster sqr at the cost of about 0.5 kB in code */
 #define BN_FAST_S_MP_SQR_C
 
+/* About 0.25 kB of code, but ~1.7kB of stack space! */
+#define BN_FAST_S_MP_MUL_DIGS_C
+
 #else /* LTM_FAST */
 
 #define BN_MP_DIV_SMALL
 
 #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
@@ -131,7 +142,9 @@ 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);
 
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
 static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+#endif
 
 #ifdef BN_MP_INIT_MULTI_C
 static int mp_init_multi(mp_int *mp, ...);
@@ -663,6 +676,9 @@ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
 #ifdef BN_MP_EXPTMOD_FAST_C
   }
 #endif
+  if (dr == 0) {
+    /* avoid compiler warnings about possibly unused variable */
+  }
 }
 
 
@@ -2331,12 +2347,14 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
   mp_word r;
   mp_digit tmpx, *tmpt, *tmpy;
 
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
   /* 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);
   }
+#endif
 
   if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
     return res;
@@ -2389,6 +2407,7 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
 }
 
 
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
 /* Fast (comba) multiplier
  *
  * This is the fast column-array [comba] multiplier.  It is 
@@ -2474,6 +2493,7 @@ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
   mp_clamp (c);
   return MP_OKAY;
 }
+#endif /* BN_FAST_S_MP_MUL_DIGS_C */
 
 
 /* init an mp_init for a given size */
index 72ebd87..b6fde5e 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #1 (RSA Encryption)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 68872b1..ed64def 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #1 (RSA Encryption)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PKCS1_H
index fd9e346..8a93483 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #5 (Password-based Encryption)
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 6ed3923..20ddadc 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #5 (Password-based Encryption)
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PKCS5_H
index 69ab262..52e43a4 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #8 (Private-key information syntax)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index dac517c..bebf840 100644 (file)
@@ -2,14 +2,8 @@
  * PKCS #8 (Private-key information syntax)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PKCS8_H
index 3084adc..125c420 100644 (file)
@@ -2,14 +2,8 @@
  * RSA
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index ac50dfd..c236a9d 100644 (file)
@@ -2,14 +2,8 @@
  * RSA
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef RSA_H
index d0da588..12148b6 100644 (file)
@@ -2,14 +2,8 @@
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -465,10 +459,8 @@ struct tlsv1_client * tlsv1_client_init(void)
 
        count = 0;
        suites = conn->cipher_suites;
-#ifndef CONFIG_CRYPTO_INTERNAL
        suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
        suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
        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;
@@ -741,10 +733,8 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
        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_SHA256;
                suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
                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;
index ef5e694..8ec85f1 100644 (file)
@@ -2,14 +2,8 @@
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_CLIENT_H
index 92912ca..55fdcf8 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 client - internal structures
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_CLIENT_I_H
index eb0cbef..3269ecf 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 client - read handshake message
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 35a238b..d789efb 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 client - write handshake message
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 871359a..d212862 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 common routines
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 027daa4..f28c0cd 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 common definitions
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_COMMON_H
index d846480..1ea6827 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 credentials
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 8425fe4..68fbdc9 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 credentials
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_CRED_H
index 0314551..3bec3be 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 Record Protocol
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 9eb9bfd..48abcb0 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 Record Protocol
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_RECORD_H
index 96e160c..2880309 100644 (file)
@@ -2,14 +2,8 @@
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -367,9 +361,7 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
 
        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;
@@ -593,16 +585,12 @@ int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
        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;
index daa4353..a18c69e 100644 (file)
@@ -2,14 +2,8 @@
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_SERVER_H
index d11ea75..1f61533 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 server - internal structures
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TLSV1_SERVER_I_H
index 443c028..6f6539b 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 server - read handshake message
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0ca3b23..6d8e55e 100644 (file)
@@ -2,14 +2,8 @@
  * TLSv1 server - write handshake message
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 347f975..06540bf 100644 (file)
@@ -2,14 +2,8 @@
  * X.509v3 certificate parsing and processing (RFC 3280 profile)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -449,17 +443,16 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
                        return -1;
                }
 
-               val = os_malloc(hdr.length + 1);
+               val = dup_binstr(hdr.payload, hdr.length);
                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);
+                       os_free(val);
                        x509_free_name(name);
                        return -1;
                }
index 3e2005b..91a35ba 100644 (file)
@@ -2,14 +2,8 @@
  * X.509v3 certificate parsing and processing
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef X509V3_H
diff --git a/src/utils/.gitignore b/src/utils/.gitignore
new file mode 100644 (file)
index 0000000..833734f
--- /dev/null
@@ -0,0 +1 @@
+libutils.a
index 0f1f191..940b4d8 100644 (file)
@@ -14,6 +14,7 @@ CFLAGS += -DCONFIG_IPV6
 
 LIB_OBJS= \
        base64.o \
+       bitfield.o \
        common.o \
        ip_addr.o \
        radiotap.o \
index fb1224b..af1307f 100644 (file)
@@ -2,14 +2,8 @@
  * Base64 encoding/decoding (RFC1341)
  * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index b87a168..aa21fd0 100644 (file)
@@ -2,14 +2,8 @@
  * Base64 encoding/decoding (RFC1341)
  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BASE64_H
diff --git a/src/utils/bitfield.c b/src/utils/bitfield.c
new file mode 100644 (file)
index 0000000..f90e4be
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "bitfield.h"
+
+
+struct bitfield {
+       u8 *bits;
+       size_t max_bits;
+};
+
+
+struct bitfield * bitfield_alloc(size_t max_bits)
+{
+       struct bitfield *bf;
+
+       bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
+       if (bf == NULL)
+               return NULL;
+       bf->bits = (u8 *) (bf + 1);
+       bf->max_bits = max_bits;
+       return bf;
+}
+
+
+void bitfield_free(struct bitfield *bf)
+{
+       os_free(bf);
+}
+
+
+void bitfield_set(struct bitfield *bf, size_t bit)
+{
+       if (bit >= bf->max_bits)
+               return;
+       bf->bits[bit / 8] |= BIT(bit % 8);
+}
+
+
+void bitfield_clear(struct bitfield *bf, size_t bit)
+{
+       if (bit >= bf->max_bits)
+               return;
+       bf->bits[bit / 8] &= ~BIT(bit % 8);
+}
+
+
+int bitfield_is_set(struct bitfield *bf, size_t bit)
+{
+       if (bit >= bf->max_bits)
+               return 0;
+       return !!(bf->bits[bit / 8] & BIT(bit % 8));
+}
+
+
+static int first_zero(u8 val)
+{
+       int i;
+       for (i = 0; i < 8; i++) {
+               if (!(val & 0x01))
+                       return i;
+               val >>= 1;
+       }
+       return -1;
+}
+
+
+int bitfield_get_first_zero(struct bitfield *bf)
+{
+       size_t i;
+       for (i = 0; i <= (bf->max_bits + 7) / 8; i++) {
+               if (bf->bits[i] != 0xff)
+                       break;
+       }
+       if (i > (bf->max_bits + 7) / 8)
+               return -1;
+       i = i * 8 + first_zero(bf->bits[i]);
+       if (i >= bf->max_bits)
+               return -1;
+       return i;
+}
diff --git a/src/utils/bitfield.h b/src/utils/bitfield.h
new file mode 100644 (file)
index 0000000..7050a20
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BITFIELD_H
+#define BITFIELD_H
+
+struct bitfield;
+
+struct bitfield * bitfield_alloc(size_t max_bits);
+void bitfield_free(struct bitfield *bf);
+void bitfield_set(struct bitfield *bf, size_t bit);
+void bitfield_clear(struct bitfield *bf, size_t bit);
+int bitfield_is_set(struct bitfield *bf, size_t bit);
+int bitfield_get_first_zero(struct bitfield *bf);
+
+#endif /* BITFIELD_H */
index 3666778..f947388 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd - Build time configuration defines
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
 #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
index 55d7123..bf326cd 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / common helper functions, etc.
  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -350,6 +344,135 @@ TCHAR * wpa_strdup_tchar(const char *str)
 #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)
@@ -366,32 +489,14 @@ TCHAR * wpa_strdup_tchar(const char *str)
  */
 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';
-
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * As UI requirements, AP's essid should indicate ascii characters
-        * whether it is alphabet or not
-        */
-#if defined TIZEN_EXT
-       /*
-       for (pos = ssid_txt; *pos != '\0'; pos++) {
-               if ((u8) *pos < 32 || (u8) *pos >= 127)
-                       *pos = '_';
-       }
-       */
-#else
-       for (pos = ssid_txt; *pos != '\0'; pos++) {
-               if ((u8) *pos < 32 || (u8) *pos >= 127)
-                       *pos = '_';
+       static char ssid_txt[32 * 4 + 1];
+
+       if (ssid == NULL) {
+               ssid_txt[0] = '\0';
+               return ssid_txt;
        }
-#endif
+
+       printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
        return ssid_txt;
 }
 
@@ -400,3 +505,120 @@ 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 = dup_binstr(value, *len);
+               if (str == NULL)
+                       return NULL;
+               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 = dup_binstr(value, tlen);
+               if (tstr == NULL)
+                       return NULL;
+
+               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;
+}
+
+
+char * dup_binstr(const void *src, size_t len)
+{
+       char *res;
+
+       if (src == NULL)
+               return NULL;
+       res = os_malloc(len + 1);
+       if (res == NULL)
+               return NULL;
+       os_memcpy(res, src, len);
+       res[len] = '\0';
+
+       return res;
+}
index 14ab297..e4f7031 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / common helper functions, etc.
  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef COMMON_H
@@ -69,12 +63,6 @@ static inline unsigned int bswap_32(unsigned int v)
 #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>
 
@@ -138,16 +126,6 @@ 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>
@@ -246,69 +224,105 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 
 /* 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]))
+static inline u16 WPA_GET_BE16(const u8 *a)
+{
+       return (a[0] << 8) | a[1];
+}
+
+static inline void WPA_PUT_BE16(u8 *a, u16 val)
+{
+       a[0] = val >> 8;
+       a[1] = val & 0xff;
+}
+
+static inline u16 WPA_GET_LE16(const u8 *a)
+{
+       return (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE16(u8 *a, u16 val)
+{
+       a[1] = val >> 8;
+       a[0] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE24(const u8 *a)
+{
+       return (a[0] << 16) | (a[1] << 8) | a[2];
+}
+
+static inline void WPA_PUT_BE24(u8 *a, u32 val)
+{
+       a[0] = (val >> 16) & 0xff;
+       a[1] = (val >> 8) & 0xff;
+       a[2] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE32(const u8 *a)
+{
+       return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
+}
+
+static inline void WPA_PUT_BE32(u8 *a, u32 val)
+{
+       a[0] = (val >> 24) & 0xff;
+       a[1] = (val >> 16) & 0xff;
+       a[2] = (val >> 8) & 0xff;
+       a[3] = val & 0xff;
+}
+
+static inline u32 WPA_GET_LE32(const u8 *a)
+{
+       return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE32(u8 *a, u32 val)
+{
+       a[3] = (val >> 24) & 0xff;
+       a[2] = (val >> 16) & 0xff;
+       a[1] = (val >> 8) & 0xff;
+       a[0] = val & 0xff;
+}
+
+static inline u64 WPA_GET_BE64(const u8 *a)
+{
+       return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
+               (((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
+               (((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
+               (((u64) a[6]) << 8) | ((u64) a[7]);
+}
+
+static inline void WPA_PUT_BE64(u8 *a, u64 val)
+{
+       a[0] = val >> 56;
+       a[1] = val >> 48;
+       a[2] = val >> 40;
+       a[3] = val >> 32;
+       a[4] = val >> 24;
+       a[5] = val >> 16;
+       a[6] = val >> 8;
+       a[7] = val & 0xff;
+}
+
+static inline u64 WPA_GET_LE64(const u8 *a)
+{
+       return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
+               (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
+               (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
+               (((u64) a[1]) << 8) | ((u64) a[0]);
+}
+
+static inline void WPA_PUT_LE64(u8 *a, u64 val)
+{
+       a[7] = val >> 56;
+       a[6] = val >> 48;
+       a[5] = val >> 40;
+       a[4] = val >> 32;
+       a[3] = val >> 24;
+       a[2] = val >> 16;
+       a[1] = val >> 8;
+       a[0] = val & 0xff;
+}
 
 
 #ifndef ETH_ALEN
@@ -463,8 +477,18 @@ TCHAR * wpa_strdup_tchar(const char *str);
 #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);
+char * dup_binstr(const void *src, size_t len);
+
 static inline int is_zero_ether_addr(const u8 *a)
 {
        return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
index c5b17ac..177ecf4 100644 (file)
@@ -2,14 +2,8 @@
  * Command line editing and history
  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -26,6 +20,7 @@ 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
 
@@ -53,7 +48,7 @@ void edit_clear_line(void)
 {
        int i;
        putchar('\r');
-       for (i = 0; i < cmdbuf_len + 2; i++)
+       for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
                putchar(' ');
 }
 
@@ -350,9 +345,9 @@ static void insert_char(int c)
 
 static void process_cmd(void)
 {
-
+       currbuf_valid = 0;
        if (cmdbuf_len == 0) {
-               printf("\n");
+               printf("\n%s> ", ps2 ? ps2 : "");
                fflush(stdout);
                return;
        }
@@ -362,7 +357,7 @@ static void process_cmd(void)
        cmdbuf_pos = 0;
        cmdbuf_len = 0;
        edit_cmd_cb(edit_cb_ctx, cmdbuf);
-       printf("");
+       printf("%s> ", ps2 ? ps2 : "");
        fflush(stdout);
 }
 
@@ -1118,7 +1113,7 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
 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)
+             void *ctx, const char *history_file, const char *ps)
 {
        currbuf[0] = '\0';
        dl_list_init(&history_list);
@@ -1138,7 +1133,8 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
 
        eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
 
-       printf("> ");
+       ps2 = ps;
+       printf("%s> ", ps2 ? ps2 : "");
        fflush(stdout);
 
        return 0;
@@ -1167,11 +1163,11 @@ void edit_redraw(void)
 {
        char tmp;
        cmdbuf[cmdbuf_len] = '\0';
-       printf("\r> %s", cmdbuf);
+       printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
        if (cmdbuf_pos != cmdbuf_len) {
                tmp = cmdbuf[cmdbuf_pos];
                cmdbuf[cmdbuf_pos] = '\0';
-               printf("\r> %s", cmdbuf);
+               printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
                cmdbuf[cmdbuf_pos] = tmp;
        }
        fflush(stdout);
index fc4474b..ad27f1c 100644 (file)
@@ -2,14 +2,8 @@
  * Command line editing and history
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EDIT_H
@@ -18,7 +12,7 @@
 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);
+             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);
index 1fef7b9..c2a5bca 100644 (file)
@@ -2,14 +2,8 @@
  * Command line editing and history wrapper for readline
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -118,7 +112,7 @@ static void readline_cmd_handler(char *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)
+             void *ctx, const char *history_file, const char *ps)
 {
        edit_cb_ctx = ctx;
        edit_cmd_cb = cmd_cb;
@@ -133,6 +127,17 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
 
        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;
@@ -142,6 +147,9 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
 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();
 
@@ -159,9 +167,9 @@ void edit_deinit(const char *history_file,
                        if (filter_cb && filter_cb(edit_cb_ctx, p)) {
                                h = remove_history(where_history());
                                if (h) {
-                                       os_free(h->line);
+                                       free(h->line);
                                        free(h->data);
-                                       os_free(h);
+                                       free(h);
                                } else
                                        next_history();
                        } else
index 61fb24e..a095ea6 100644 (file)
@@ -2,14 +2,8 @@
  * Minimal command line editing
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -22,6 +16,7 @@
 #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);
@@ -47,7 +42,7 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
                cmdbuf[cmdbuf_pos] = '\0';
                cmdbuf_pos = 0;
                edit_cmd_cb(edit_cb_ctx, cmdbuf);
-               printf("");
+               printf("%s> ", ps2 ? ps2 : "");
                fflush(stdout);
                return;
        }
@@ -63,14 +58,15 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
 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)
+             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("");
+       printf("%s> ", ps2 ? ps2 : "");
        fflush(stdout);
 
        return 0;
index b550c63..f62e2b7 100644 (file)
@@ -2,14 +2,8 @@
  * Event loop based on select() loop
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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;
@@ -57,6 +56,13 @@ struct eloop_sock_table {
 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;
@@ -134,14 +140,44 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
                                      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 = (struct eloop_sock *)
-               os_realloc(table->table,
-                          (table->count + 1) * sizeof(struct eloop_sock));
+       tmp = os_realloc_array(table->table, table->count + 1,
+                              sizeof(struct eloop_sock));
        if (tmp == NULL)
                return -1;
 
@@ -152,8 +188,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
        wpa_trace_record(&tmp[table->count]);
        table->count++;
        table->table = tmp;
-       if (sock > eloop.max_sock)
-               eloop.max_sock = sock;
+       eloop.max_sock = new_max_sock;
+       eloop.count++;
        table->changed = 1;
        eloop_trace_sock_add_ref(table);
 
@@ -182,11 +218,152 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
                           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)
 {
@@ -222,6 +399,8 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
        }
 }
 
+#endif /* CONFIG_ELOOP_POLL */
+
 
 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
 {
@@ -377,6 +556,33 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
 }
 
 
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+                            void *eloop_data, void *user_data,
+                            struct os_time *remaining)
+{
+       struct eloop_timeout *timeout, *prev;
+       int removed = 0;
+       struct os_time now;
+
+       os_get_time(&now);
+       remaining->sec = remaining->usec = 0;
+
+       dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+                             struct eloop_timeout, list) {
+               if (timeout->handler == handler &&
+                   (timeout->eloop_data == eloop_data) &&
+                   (timeout->user_data == user_data)) {
+                       removed = 1;
+                       if (os_time_before(&now, &timeout->time))
+                               os_time_sub(&timeout->time, &now, remaining);
+                       eloop_remove_timeout(timeout);
+                       break;
+               }
+       }
+       return removed;
+}
+
+
 int eloop_is_timeout_registered(eloop_timeout_handler handler,
                                void *eloop_data, void *user_data)
 {
@@ -460,10 +666,8 @@ int eloop_register_signal(int sig, eloop_signal_handler handler,
 {
        struct eloop_signal *tmp;
 
-       tmp = (struct eloop_signal *)
-               os_realloc(eloop.signals,
-                          (eloop.signal_count + 1) *
-                          sizeof(struct eloop_signal));
+       tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+                              sizeof(struct eloop_signal));
        if (tmp == NULL)
                return -1;
 
@@ -502,16 +706,23 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
 
 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;
-       int res;
        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 ||
@@ -525,10 +736,27 @@ void eloop_run(void)
                                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);
@@ -538,6 +766,7 @@ void eloop_run(void)
                        perror("select");
                        goto out;
                }
+#endif /* CONFIG_ELOOP_POLL */
                eloop_process_pending_signals();
 
                /* check if some registered timeouts have occurred */
@@ -559,15 +788,25 @@ void eloop_run(void)
                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 */
        }
 
+       eloop.terminate = 0;
 out:
+#ifndef CONFIG_ELOOP_POLL
        os_free(rfds);
        os_free(wfds);
        os_free(efds);
+#endif /* CONFIG_ELOOP_POLL */
+       return;
 }
 
 
@@ -605,6 +844,11 @@ void eloop_destroy(void)
        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 */
 }
 
 
@@ -616,6 +860,18 @@ int eloop_terminated(void)
 
 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)
@@ -624,4 +880,5 @@ void eloop_wait_for_read_sock(int sock)
        FD_ZERO(&rfds);
        FD_SET(sock, &rfds);
        select(sock + 1, &rfds, NULL, NULL, NULL);
+#endif /* CONFIG_ELOOP_POLL */
 }
index a656bf8..0037c63 100644 (file)
@@ -2,14 +2,8 @@
  * Event loop
  * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -201,6 +195,21 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
                         void *eloop_data, void *user_data);
 
 /**
+ * eloop_cancel_timeout_one - Cancel a single timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * @remaining: Time left on the cancelled timer
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeout registered with
+ * eloop_register_timeout() and return the remaining time left.
+ */
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+                            void *eloop_data, void *user_data,
+                            struct os_time *remaining);
+
+/**
  * eloop_is_timeout_registered - Check if a timeout is already registered
  * @handler: Matching callback function
  * @eloop_data: Matching eloop_data
index 18eae4e..cb5e922 100644 (file)
@@ -1,20 +1,15 @@
 /*
  * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 
 #include "common.h"
+#include "list.h"
 #include "eloop.h"
 
 
@@ -22,21 +17,21 @@ struct eloop_sock {
        int sock;
        void *eloop_data;
        void *user_data;
-       void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+       eloop_sock_handler handler;
 };
 
 struct eloop_timeout {
+       struct dl_list list;
        struct os_time time;
        void *eloop_data;
        void *user_data;
-       void (*handler)(void *eloop_ctx, void *sock_ctx);
-       struct eloop_timeout *next;
+       eloop_timeout_handler handler;
 };
 
 struct eloop_signal {
        int sig;
        void *user_data;
-       void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+       eloop_signal_handler handler;
        int signaled;
 };
 
@@ -44,7 +39,7 @@ struct eloop_data {
        int max_sock, reader_count;
        struct eloop_sock *readers;
 
-       struct eloop_timeout *timeout;
+       struct dl_list timeout;
 
        int signal_count;
        struct eloop_signal *signals;
@@ -60,21 +55,19 @@ static struct eloop_data eloop;
 
 int eloop_init(void)
 {
-       memset(&eloop, 0, sizeof(eloop));
+       os_memset(&eloop, 0, sizeof(eloop));
+       dl_list_init(&eloop.timeout);
        return 0;
 }
 
 
-int eloop_register_read_sock(int sock,
-                            void (*handler)(int sock, void *eloop_ctx,
-                                            void *sock_ctx),
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
                             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));
+       tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+                              sizeof(struct eloop_sock));
        if (tmp == NULL)
                return -1;
 
@@ -106,9 +99,9 @@ void eloop_unregister_read_sock(int sock)
        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));
+               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;
@@ -116,16 +109,31 @@ void eloop_unregister_read_sock(int sock)
 
 
 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-                          void (*handler)(void *eloop_ctx, void *timeout_ctx),
+                          eloop_timeout_handler handler,
                           void *eloop_data, void *user_data)
 {
-       struct eloop_timeout *timeout, *tmp, *prev;
+       struct eloop_timeout *timeout, *tmp;
+       os_time_t now_sec;
 
-       timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+       timeout = os_zalloc(sizeof(*timeout));
        if (timeout == NULL)
                return -1;
-       os_get_time(&timeout->time);
+       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++;
@@ -134,80 +142,86 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
        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;
+       /* 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);
 
-       prev = NULL;
-       tmp = eloop.timeout;
-       while (tmp != NULL) {
-               if (os_time_before(&timeout->time, &tmp->time))
-                       break;
-               prev = tmp;
-               tmp = tmp->next;
-       }
+       return 0;
+}
 
-       if (prev == NULL) {
-               timeout->next = eloop.timeout;
-               eloop.timeout = timeout;
-       } else {
-               timeout->next = prev->next;
-               prev->next = timeout;
-       }
 
-       return 0;
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+       dl_list_del(&timeout->list);
+       os_free(timeout);
 }
 
 
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+int eloop_cancel_timeout(eloop_timeout_handler handler,
                         void *eloop_data, void *user_data)
 {
-       struct eloop_timeout *timeout, *prev, *next;
+       struct eloop_timeout *timeout, *prev;
        int removed = 0;
 
-       prev = NULL;
-       timeout = eloop.timeout;
-       while (timeout != NULL) {
-               next = timeout->next;
-
+       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)) {
-                       if (prev == NULL)
-                               eloop.timeout = next;
-                       else
-                               prev->next = next;
-                       free(timeout);
+                       eloop_remove_timeout(timeout);
                        removed++;
-               } else
-                       prev = timeout;
-
-               timeout = next;
+               }
        }
 
        return removed;
 }
 
 
-int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
-                                               void *timeout_ctx),
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+                            void *eloop_data, void *user_data,
+                            struct os_time *remaining)
+{
+       struct eloop_timeout *timeout, *prev;
+       int removed = 0;
+       struct os_time now;
+
+       os_get_time(&now);
+       remaining->sec = remaining->usec = 0;
+
+       dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+                             struct eloop_timeout, list) {
+               if (timeout->handler == handler &&
+                   (timeout->eloop_data == eloop_data) &&
+                   (timeout->user_data == user_data)) {
+                       removed = 1;
+                       if (os_time_before(&now, &timeout->time))
+                               os_time_sub(&timeout->time, &now, remaining);
+                       eloop_remove_timeout(timeout);
+                       break;
+               }
+       }
+       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) {
+       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;
-
-               tmp = tmp->next;
        }
 
        return 0;
@@ -247,24 +261,19 @@ static void eloop_process_pending_signals(void)
                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),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
                          void *user_data)
 {
        struct eloop_signal *tmp;
 
-       tmp = (struct eloop_signal *)
-               realloc(eloop.signals,
-                       (eloop.signal_count + 1) *
-                       sizeof(struct eloop_signal));
+       tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+                              sizeof(struct eloop_signal));
        if (tmp == NULL)
                return -1;
 
@@ -281,8 +290,7 @@ int eloop_register_signal(int sig,
 }
 
 
-int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
-                                                   void *signal_ctx),
+int eloop_register_signal_terminate(eloop_signal_handler handler,
                                    void *user_data)
 {
 #if 0
@@ -296,8 +304,7 @@ int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
 }
 
 
-int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
-                                                  void *signal_ctx),
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
                                   void *user_data)
 {
 #if 0
@@ -314,11 +321,14 @@ void eloop_run(void)
        struct os_time tv, now;
 
        while (!eloop.terminate &&
-               (eloop.timeout || eloop.reader_count > 0)) {
-               if (eloop.timeout) {
+               (!dl_list_empty(&eloop.timeout) || eloop.reader_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, &eloop.timeout->time))
-                               os_time_sub(&eloop.timeout->time, &now, &tv);
+                       if (os_time_before(&now, &timeout->time))
+                               os_time_sub(&timeout->time, &now, &tv);
                        else
                                tv.sec = tv.usec = 0;
                }
@@ -332,16 +342,17 @@ void eloop_run(void)
                eloop_process_pending_signals();
 
                /* check if some registered timeouts have occurred */
-               if (eloop.timeout) {
-                       struct eloop_timeout *tmp;
-
+               timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+                                       list);
+               if (timeout) {
                        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);
+                       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);
                        }
 
                }
@@ -375,14 +386,12 @@ void eloop_destroy(void)
 {
        struct eloop_timeout *timeout, *prev;
 
-       timeout = eloop.timeout;
-       while (timeout != NULL) {
-               prev = timeout;
-               timeout = timeout->next;
-               free(prev);
+       dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+                             struct eloop_timeout, list) {
+               eloop_remove_timeout(timeout);
        }
-       free(eloop.readers);
-       free(eloop.signals);
+       os_free(eloop.readers);
+       os_free(eloop.signals);
 }
 
 
index c726ece..eda412f 100644 (file)
@@ -1,21 +1,16 @@
 /*
  * Event loop based on Windows events and WaitForMultipleObjects
- * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 "list.h"
 #include "eloop.h"
 
 
@@ -35,11 +30,11 @@ struct eloop_event {
 };
 
 struct eloop_timeout {
+       struct dl_list list;
        struct os_time time;
        void *eloop_data;
        void *user_data;
        eloop_timeout_handler handler;
-       struct eloop_timeout *next;
 };
 
 struct eloop_signal {
@@ -57,7 +52,7 @@ struct eloop_data {
        size_t event_count;
        struct eloop_event *events;
 
-       struct eloop_timeout *timeout;
+       struct dl_list timeout;
 
        int signal_count;
        struct eloop_signal *signals;
@@ -80,6 +75,7 @@ static struct eloop_data eloop;
 int eloop_init(void)
 {
        os_memset(&eloop, 0, sizeof(eloop));
+       dl_list_init(&eloop.timeout);
        eloop.num_handles = 1;
        eloop.handles = os_malloc(eloop.num_handles *
                                  sizeof(eloop.handles[0]));
@@ -104,8 +100,8 @@ static int eloop_prepare_handles(void)
 
        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]));
+       n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
+                            sizeof(eloop.handles[0]));
        if (n == NULL)
                return -1;
        eloop.handles = n;
@@ -134,8 +130,8 @@ int eloop_register_read_sock(int sock, eloop_sock_handler handler,
                WSACloseEvent(event);
                return -1;
        }
-       tmp = os_realloc(eloop.readers,
-                        (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+       tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+                              sizeof(struct eloop_sock));
        if (tmp == NULL) {
                WSAEventSelect(sock, event, 0);
                WSACloseEvent(event);
@@ -197,8 +193,8 @@ int eloop_register_event(void *event, size_t event_size,
        if (eloop_prepare_handles())
                return -1;
 
-       tmp = os_realloc(eloop.events,
-                        (eloop.event_count + 1) * sizeof(struct eloop_event));
+       tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
+                              sizeof(struct eloop_event));
        if (tmp == NULL)
                return -1;
 
@@ -242,13 +238,16 @@ 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;
+       struct eloop_timeout *timeout, *tmp;
        os_time_t now_sec;
 
-       timeout = os_malloc(sizeof(*timeout));
+       timeout = os_zalloc(sizeof(*timeout));
        if (timeout == NULL)
                return -1;
-       os_get_time(&timeout->time);
+       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) {
@@ -269,79 +268,86 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
        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;
+       /* 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);
 
-       prev = NULL;
-       tmp = eloop.timeout;
-       while (tmp != NULL) {
-               if (os_time_before(&timeout->time, &tmp->time))
-                       break;
-               prev = tmp;
-               tmp = tmp->next;
-       }
+       return 0;
+}
 
-       if (prev == NULL) {
-               timeout->next = eloop.timeout;
-               eloop.timeout = timeout;
-       } else {
-               timeout->next = prev->next;
-               prev->next = timeout;
-       }
 
-       return 0;
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+       dl_list_del(&timeout->list);
+       os_free(timeout);
 }
 
 
 int eloop_cancel_timeout(eloop_timeout_handler handler,
                         void *eloop_data, void *user_data)
 {
-       struct eloop_timeout *timeout, *prev, *next;
+       struct eloop_timeout *timeout, *prev;
        int removed = 0;
 
-       prev = NULL;
-       timeout = eloop.timeout;
-       while (timeout != NULL) {
-               next = timeout->next;
-
+       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)) {
-                       if (prev == NULL)
-                               eloop.timeout = next;
-                       else
-                               prev->next = next;
-                       os_free(timeout);
+                       eloop_remove_timeout(timeout);
                        removed++;
-               } else
-                       prev = timeout;
-
-               timeout = next;
+               }
        }
 
        return removed;
 }
 
 
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+                            void *eloop_data, void *user_data,
+                            struct os_time *remaining)
+{
+       struct eloop_timeout *timeout, *prev;
+       int removed = 0;
+       struct os_time now;
+
+       os_get_time(&now);
+       remaining->sec = remaining->usec = 0;
+
+       dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+                             struct eloop_timeout, list) {
+               if (timeout->handler == handler &&
+                   (timeout->eloop_data == eloop_data) &&
+                   (timeout->user_data == user_data)) {
+                       removed = 1;
+                       if (os_time_before(&now, &timeout->time))
+                               os_time_sub(&timeout->time, &now, remaining);
+                       eloop_remove_timeout(timeout);
+                       break;
+               }
+       }
+       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) {
+       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;
-
-               tmp = tmp->next;
        }
 
        return 0;
@@ -398,9 +404,8 @@ int eloop_register_signal(int sig, eloop_signal_handler handler,
 {
        struct eloop_signal *tmp;
 
-       tmp = os_realloc(eloop.signals,
-                        (eloop.signal_count + 1) *
-                        sizeof(struct eloop_signal));
+       tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+                              sizeof(struct eloop_signal));
        if (tmp == NULL)
                return -1;
 
@@ -464,17 +469,20 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
 void eloop_run(void)
 {
        struct os_time tv, now;
-       DWORD count, ret, timeout, err;
+       DWORD count, ret, timeout_val, err;
        size_t i;
 
        while (!eloop.terminate &&
-              (eloop.timeout || eloop.reader_count > 0 ||
+              (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
                eloop.event_count > 0)) {
+               struct eloop_timeout *timeout;
                tv.sec = tv.usec = 0;
-               if (eloop.timeout) {
+               timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+                                       list);
+               if (timeout) {
                        os_get_time(&now);
-                       if (os_time_before(&now, &eloop.timeout->time))
-                               os_time_sub(&eloop.timeout->time, &now, &tv);
+                       if (os_time_before(&now, &timeout->time))
+                               os_time_sub(&timeout->time, &now, &tv);
                }
 
                count = 0;
@@ -487,10 +495,10 @@ void eloop_run(void)
                if (eloop.term_event)
                        eloop.handles[count++] = eloop.term_event;
 
-               if (eloop.timeout)
-                       timeout = tv.sec * 1000 + tv.usec / 1000;
+               if (timeout)
+                       timeout_val = tv.sec * 1000 + tv.usec / 1000;
                else
-                       timeout = INFINITE;
+                       timeout_val = INFINITE;
 
                if (count > MAXIMUM_WAIT_OBJECTS) {
                        printf("WaitForMultipleObjects: Too many events: "
@@ -500,26 +508,27 @@ void eloop_run(void)
                }
 #ifdef _WIN32_WCE
                ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
-                                            timeout);
+                                            timeout_val);
 #else /* _WIN32_WCE */
                ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
-                                              timeout, TRUE);
+                                              timeout_val, TRUE);
 #endif /* _WIN32_WCE */
                err = GetLastError();
 
                eloop_process_pending_signals();
 
                /* check if some registered timeouts have occurred */
-               if (eloop.timeout) {
-                       struct eloop_timeout *tmp;
-
+               timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+                                       list);
+               if (timeout) {
                        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 (!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);
                        }
 
                }
@@ -578,11 +587,9 @@ void eloop_destroy(void)
 {
        struct eloop_timeout *timeout, *prev;
 
-       timeout = eloop.timeout;
-       while (timeout != NULL) {
-               prev = timeout;
-               timeout = timeout->next;
-               os_free(prev);
+       dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+                             struct eloop_timeout, list) {
+               eloop_remove_timeout(timeout);
        }
        os_free(eloop.readers);
        os_free(eloop.signals);
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
new file mode 100644 (file)
index 0000000..0613119
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef __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);
+}
diff --git a/src/utils/ext_password.h b/src/utils/ext_password.h
new file mode 100644 (file)
index 0000000..e3e46ea
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@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 */
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
new file mode 100644 (file)
index 0000000..043e731
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * External password backend - internal definitions
+ * Copyright (c) 2012, Jouni Malinen <j@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 */
diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c
new file mode 100644 (file)
index 0000000..3801bb8
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "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,
+};
index cf2a42b..6c6ec87 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd - Default include files
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -47,9 +41,7 @@
 #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 */
index 158fd57..3647c76 100644 (file)
@@ -2,14 +2,8 @@
  * IP address processing
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 28ccaef..79ac20c 100644 (file)
@@ -2,14 +2,8 @@
  * IP address processing
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IP_ADDR_H
index c8dccee..6881130 100644 (file)
@@ -2,14 +2,8 @@
  * Doubly-linked list
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef LIST_H
index f69478a..ad20834 100644 (file)
@@ -2,14 +2,8 @@
  * OS specific functions
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef OS_H
@@ -186,6 +180,25 @@ char * os_readfile(const char *name, size_t *len);
  */
 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.
@@ -473,6 +486,14 @@ char * os_strdup(const char *s);
 #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
index 8024a30..e4b7fdb 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / Internal implementation of OS specific functions
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index 3fbb777..cabf73b 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / Empty OS specific functions
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index 9b16b33..40ad9d4 100644 (file)
@@ -2,14 +2,8 @@
  * OS specific functions for UNIX/POSIX systems
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -219,6 +213,9 @@ char * os_rel2abs_path(const char *rel_path)
        size_t len = 128, cwd_len, rel_len, ret_len;
        int last_errno;
 
+       if (!rel_path)
+               return NULL;
+
        if (rel_path[0] == '/')
                return os_strdup(rel_path);
 
@@ -263,7 +260,11 @@ int os_program_init(void)
         * We ignore errors here since errors are normal if we
         * are already running as non-root.
         */
+#ifdef ANDROID_SETGROUPS_OVERRIDE
+       gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
+#else /* ANDROID_SETGROUPS_OVERRIDE */
        gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+#endif /* ANDROID_SETGROUPS_OVERRIDE */
        struct __user_cap_header_struct header;
        struct __user_cap_data_struct cap;
 
index 51bd545..163cebe 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / OS specific functions for Win32 systems
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index c36193e..08510d0 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -76,6 +70,9 @@
 #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 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 {
@@ -240,37 +258,60 @@ static int scard_read_record(struct scard_data *scard,
 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;
+       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) {
+               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
@@ -279,21 +320,43 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
                                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 &&
+                       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];
+               pos += 2 + pos[1];
 
-                       if (pos == end)
-                               return 0;
-               }
-               return -1;
+               if (pos == end)
+                       return 0;
+       }
+       return -1;
 }
 
 
@@ -334,7 +397,7 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
                unsigned char rid[5];
                unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
        } *efdir;
-       unsigned char buf[100];
+       unsigned char buf[127];
        size_t blen;
 
        efdir = (struct efdir *) buf;
@@ -423,6 +486,7 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
 /**
  * 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
@@ -431,10 +495,10 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
  * 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)
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
 {
        long ret;
-       unsigned long len;
+       unsigned long len, pos;
        struct scard_data *scard;
 #ifdef CONFIG_NATIVE_WINDOWS
        TCHAR *readers = NULL;
@@ -488,18 +552,41 @@ struct scard_data * scard_init(scard_sim_type sim_type)
                           "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.. */
+       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
-       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
+       /* TODO */
 #else /* UNICODE */
-       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+       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;
+       }
 
-       ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
-                          SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
+#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.");
@@ -588,7 +675,8 @@ struct scard_data * scard_init(scard_sim_type sim_type)
        }
        if (pin_needed) {
                scard->pin1_required = 1;
-               wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+               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);
@@ -945,6 +1033,46 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin)
 }
 
 
+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()
@@ -1024,6 +1152,61 @@ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
 
 
 /**
+ * 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
@@ -1236,3 +1419,9 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
        wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
        return -1;
 }
+
+
+int scard_supports_umts(struct scard_data *scard)
+{
+       return scard->sim_type == SCARD_USIM;
+}
index 543f7c5..b4ebc99 100644 (file)
@@ -1,39 +1,14 @@
 /*
  * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2006, 2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README 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,
@@ -42,26 +17,32 @@ typedef enum {
 
 
 #ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type);
+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) NULL
+#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 */
 
index 31f6672..a514315 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd - State machine definitions
  * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
index bb3eb24..6795d41 100644 (file)
@@ -2,14 +2,8 @@
  * Backtrace debugging
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 22d3de0..38f43fb 100644 (file)
@@ -2,14 +2,8 @@
  * Backtrace debugging
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef TRACE_H
index d8cc267..2aa4bcb 100644 (file)
@@ -2,14 +2,8 @@
  * Universally Unique IDentifier (UUID)
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0759165..5e860cb 100644 (file)
@@ -2,14 +2,8 @@
  * Universally Unique IDentifier (UUID)
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef UUID_H
index aa7295c..38ea8aa 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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;
@@ -36,68 +42,29 @@ int wpa_debug_timestamp = 0;
 #define ANDROID_LOG_NAME       "wpa_supplicant"
 #endif /* ANDROID_LOG_NAME */
 
-void android_printf(int level, char *format, ...)
+static int wpa_to_android_level(int level)
 {
-       if (level >= wpa_debug_level) {
-               va_list ap;
-               if (level == MSG_ERROR)
-                       level = ANDROID_LOG_ERROR;
-               else if (level == MSG_WARNING)
-                       level = ANDROID_LOG_WARN;
-               else if (level == MSG_INFO)
-                       level = ANDROID_LOG_INFO;
-               else
-                       level = ANDROID_LOG_DEBUG;
-               va_start(ap, format);
-               __android_log_vprint(level, ANDROID_LOG_NAME, format, ap);
-               va_end(ap);
-       }
+       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;
 }
 
-#else /* CONFIG_ANDROID_LOG */
+#endif /* CONFIG_ANDROID_LOG */
 
 #ifndef CONFIG_NO_STDOUT_DEBUG
 
 #ifdef CONFIG_DEBUG_FILE
 static FILE *out_file = NULL;
-#if defined TIZEN_EXT
-#include <time.h>
-#include <sys/stat.h>
-
-static char *out_file_name = NULL;
-#endif
 #endif /* CONFIG_DEBUG_FILE */
 
 
 void wpa_debug_print_timestamp(void)
 {
-#if defined TIZEN_EXT
-       struct os_time tv;
-
-       /*
-        * Oct, 26th. 2011. TIZEN
-        * Change time log's display expression like year-month-day hour:min:sec.milisec
-        */
-
-       struct tm *ptm;
-       char time_string[40];
-
-       if (!wpa_debug_timestamp)
-               return;
-
-       os_get_time(&tv);
-
-       ptm = (struct tm *)localtime(&tv.sec);
-       strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm);
-
-#ifdef CONFIG_DEBUG_FILE
-       if (out_file) {
-               fprintf(out_file, "%s.%06u: ", time_string,
-                       (unsigned int) tv.usec);
-       } else
-#endif /* CONFIG_DEBUG_FILE */
-       printf("%s.%06u: ", time_string, (unsigned int) tv.usec);
-#else
+#ifndef CONFIG_ANDROID_LOG
        struct os_time tv;
 
        if (!wpa_debug_timestamp)
@@ -111,8 +78,7 @@ void wpa_debug_print_timestamp(void)
        } else
 #endif /* CONFIG_DEBUG_FILE */
        printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
-
-#endif
+#endif /* CONFIG_ANDROID_LOG */
 }
 
 
@@ -153,76 +119,76 @@ static int syslog_priority(int level)
 #endif /* CONFIG_DEBUG_SYSLOG */
 
 
-#ifdef CONFIG_DEBUG_FILE
-#if defined TIZEN_EXT
-
-#define MAX_LOG_SIZE   2 * 1024 * 1024
-#define MAX_LOG_COUNT  9
+#ifdef CONFIG_DEBUG_LINUX_TRACING
 
-static char *__wpa_strdup_vprintf(const char *format, va_list va)
+int wpa_debug_open_linux_tracing(void)
 {
-       char *string = NULL;
-
-       int len = vasprintf(&string, format, va);
-       if (len < 0)
-               string = NULL;
-
-       return string;
-}
-
-static char *__wpa_strdup_printf(const char *format, ...)
-{
-       char *buffer = NULL;
-       va_list va;
-
-       va_start(va, format);
-       buffer = __wpa_strdup_vprintf(format, va);
-       va_end(va);
-
-       return buffer;
-}
+       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;
+       }
 
-static void __wpa_log_update_file_revision(int rev)
-{
-       int next_log_rev = 0;
-       char *log_file = NULL;
-       char *next_log_file = NULL;
+       buflen = read(mounts, buf, sizeof(buf) - 1);
+       close(mounts);
+       if (buflen < 0) {
+               printf("failed to read /proc/mounts\n");
+               return -1;
+       }
 
-       next_log_rev = rev + 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;
+               }
 
-       log_file = __wpa_strdup_printf("%s.%d", out_file_name, rev);
-       next_log_file = __wpa_strdup_printf("%s.%d", out_file_name, next_log_rev);
+               line = strtok_r(NULL, "\n", &tmp1);
+       }
 
-       if (next_log_rev >= MAX_LOG_COUNT)
-               remove(next_log_file);
+       if (path == NULL) {
+               printf("debugfs mountpoint not found\n");
+               return -1;
+       }
 
-       if (access(next_log_file, F_OK) == 0)
-               __wpa_log_update_file_revision(next_log_rev);
+       snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
 
-       if (rename(log_file, next_log_file) != 0)
-               remove(log_file);
+       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;
+       }
 
-       os_free(log_file);
-       os_free(next_log_file);
+       return 0;
 }
 
-static void __wpa_log_make_backup(void)
-{
-       const int rev = 0;
-       char *backup = NULL;
-
-       backup = __wpa_strdup_printf("%s.%d", out_file_name, rev);
 
-       if (access(backup, F_OK) == 0)
-               __wpa_log_update_file_revision(rev);
+void wpa_debug_close_linux_tracing(void)
+{
+       if (wpa_debug_tracing_file == NULL)
+               return;
+       fclose(wpa_debug_tracing_file);
+       wpa_debug_tracing_file = NULL;
+}
 
-       if (rename(out_file_name, backup) != 0)
-               remove(out_file_name);
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
-       os_free(backup);
-}
-#endif /* TIZEN_EXT */
-#endif /* CONFIG_DEBUG_FILE */
 
 /**
  * wpa_printf - conditional printf
@@ -241,6 +207,10 @@ void wpa_printf(int level, const char *fmt, ...)
 
        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);
@@ -249,24 +219,6 @@ void wpa_printf(int level, const char *fmt, ...)
                wpa_debug_print_timestamp();
 #ifdef CONFIG_DEBUG_FILE
                if (out_file) {
-#if defined TIZEN_EXT
-                       struct stat buf;
-
-                       fstat(fileno(out_file), &buf);
-                       if (buf.st_size >= MAX_LOG_SIZE) {
-                               fclose(out_file);
-                               out_file = NULL;
-
-                               __wpa_log_make_backup();
-
-                               out_file = fopen(out_file_name, "a");
-                               if (out_file == NULL) {
-                                       wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
-                                                       "output file, using standard output");
-                                       return;
-                               }
-                       }
-#endif
                        vfprintf(out_file, fmt, ap);
                        fprintf(out_file, "\n");
                } else {
@@ -279,8 +231,20 @@ void wpa_printf(int level, const char *fmt, ...)
 #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 */
 }
 
 
@@ -288,8 +252,97 @@ 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) {
@@ -319,6 +372,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
 #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)
@@ -340,8 +394,30 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
        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) {
@@ -415,6 +491,7 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
 #ifdef CONFIG_DEBUG_FILE
        }
 #endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
 }
 
 
@@ -474,9 +551,6 @@ int wpa_debug_open_file(const char *path)
                           "output file, using standard output");
                return -1;
        }
-#if defined TIZEN_EXT
-       out_file_name = os_strdup(path);
-#endif
 #ifndef _WIN32
        setvbuf(out_file, NULL, _IOLBF, 0);
 #endif /* _WIN32 */
@@ -494,18 +568,11 @@ void wpa_debug_close_file(void)
        out_file = NULL;
        os_free(last_path);
        last_path = NULL;
-#if defined TIZEN_EXT
-       if (out_file_name != NULL) {
-               os_free(out_file_name);
-               out_file_name = NULL;
-       }
-#endif
 #endif /* CONFIG_DEBUG_FILE */
 }
 
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-#endif /* CONFIG_ANDROID_LOG */
 
 #ifndef CONFIG_NO_WPA_MSG
 static wpa_msg_cb_func wpa_msg_cb = NULL;
@@ -553,7 +620,7 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
        va_end(ap);
        wpa_printf(level, "%s%s", prefix, buf);
        if (wpa_msg_cb)
-               wpa_msg_cb(ctx, level, buf, len);
+               wpa_msg_cb(ctx, level, 0, buf, len);
        os_free(buf);
 }
 
@@ -577,9 +644,56 @@ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
        va_start(ap, fmt);
        len = vsnprintf(buf, buflen, fmt, ap);
        va_end(ap);
-       wpa_msg_cb(ctx, level, buf, len);
+       wpa_msg_cb(ctx, level, 0, buf, len);
        os_free(buf);
 }
+
+
+void wpa_msg_global(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_global: Failed to allocate "
+                          "message buffer");
+               return;
+       }
+       va_start(ap, fmt);
+       len = vsnprintf(buf, buflen, fmt, ap);
+       va_end(ap);
+       wpa_printf(level, "%s", buf);
+       if (wpa_msg_cb)
+               wpa_msg_cb(ctx, level, 1, buf, len);
+       os_free(buf);
+}
+
+
+void wpa_msg_no_global(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_no_global: Failed to allocate "
+                          "message buffer");
+               return;
+       }
+       va_start(ap, fmt);
+       len = vsnprintf(buf, buflen, fmt, ap);
+       va_end(ap);
+       wpa_printf(level, "%s", buf);
+       if (wpa_msg_cb)
+               wpa_msg_cb(ctx, level, 2, buf, len);
+       os_free(buf);
+}
+
 #endif /* CONFIG_NO_WPA_MSG */
 
 
index 64ada57..2ed1bd8 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_DEBUG_H
@@ -24,32 +18,6 @@ enum {
        MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
 };
 
-#ifdef CONFIG_ANDROID_LOG
-
-#define wpa_debug_print_timestamp() do {} while (0)
-#define wpa_hexdump(...)            do {} while (0)
-#define wpa_hexdump_key(...)        do {} while (0)
-#define wpa_hexdump_buf(l,t,b)      do {} while (0)
-#define wpa_hexdump_buf_key(l,t,b)  do {} while (0)
-#define wpa_hexdump_ascii(...)      do {} while (0)
-#define wpa_hexdump_ascii_key(...)  do {} while (0)
-#define wpa_debug_open_file(...)    do {} while (0)
-#define wpa_debug_close_file()      do {} while (0)
-#define wpa_dbg(...)                do {} while (0)
-
-static inline int wpa_debug_reopen_file(void)
-{
-       return 0;
-}
-
-
-void android_printf(int level, char *format, ...)
-PRINTF_FORMAT(2, 3);
-
-#define wpa_printf android_printf
-
-#else /* CONFIG_ANDROID_LOG */
-
 #ifdef CONFIG_NO_STDOUT_DEBUG
 
 #define wpa_debug_print_timestamp() do { } while (0)
@@ -183,12 +151,12 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-#endif /* CONFIG_ANDROID_LOG */
-
 
 #ifdef CONFIG_NO_WPA_MSG
 #define wpa_msg(args...) do { } while (0)
 #define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_global(args...) do { } while (0)
+#define wpa_msg_no_global(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 */
@@ -223,8 +191,38 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
 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_global - Global 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 as a global event,
+ * i.e., without being specific to an interface. For backwards compatibility,
+ * an old style event is also delivered on one of the interfaces (the one
+ * specified by the context data).
+ */
+void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_no_global - 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 does not send the output as a global
+ * event.
+ */
+void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, int global,
+                               const char *txt, size_t len);
 
 /**
  * wpa_msg_register_cb - Register callback function for wpa_msg() messages
@@ -289,6 +287,24 @@ 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)                                                 \
index eda779e..b257b36 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -74,12 +68,12 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
 
        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 (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->ext_data = nbuf;
+                       buf->buf = nbuf;
                } else {
 #ifdef WPA_TRACE
                        nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
@@ -101,6 +95,7 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
                        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;
@@ -132,6 +127,7 @@ struct wpabuf * wpabuf_alloc(size_t len)
 #endif /* WPA_TRACE */
 
        buf->size = len;
+       buf->buf = (u8 *) (buf + 1);
        return buf;
 }
 
@@ -154,7 +150,8 @@ struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
 
        buf->size = len;
        buf->used = len;
-       buf->ext_data = data;
+       buf->buf = data;
+       buf->flags |= WPABUF_FLAG_EXT_DATA;
 
        return buf;
 }
@@ -195,12 +192,14 @@ void wpabuf_free(struct wpabuf *buf)
                wpa_trace_show("wpabuf_free magic mismatch");
                abort();
        }
-       os_free(buf->ext_data);
+       if (buf->flags & WPABUF_FLAG_EXT_DATA)
+               os_free(buf->buf);
        os_free(trace);
 #else /* WPA_TRACE */
        if (buf == NULL)
                return;
-       os_free(buf->ext_data);
+       if (buf->flags & WPABUF_FLAG_EXT_DATA)
+               os_free(buf->buf);
        os_free(buf);
 #endif /* WPA_TRACE */
 }
index cccfcc8..dbce925 100644 (file)
@@ -1,20 +1,17 @@
 /*
  * Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -23,8 +20,8 @@
 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 */
+       u8 *buf; /* pointer to the head of the buffer */
+       unsigned int flags;
        /* optionally followed by the allocated buffer */
 };
 
@@ -78,9 +75,7 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
  */
 static inline const void * wpabuf_head(const struct wpabuf *buf)
 {
-       if (buf->ext_data)
-               return buf->ext_data;
-       return buf + 1;
+       return buf->buf;
 }
 
 static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
@@ -95,9 +90,7 @@ static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
  */
 static inline void * wpabuf_mhead(struct wpabuf *buf)
 {
-       if (buf->ext_data)
-               return buf->ext_data;
-       return buf + 1;
+       return buf->buf;
 }
 
 static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
@@ -156,7 +149,8 @@ static inline void wpabuf_put_buf(struct wpabuf *dst,
 
 static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
 {
-       buf->ext_data = (u8 *) data;
+       buf->buf = (u8 *) data;
+       buf->flags = WPABUF_FLAG_EXT_DATA;
        buf->size = buf->used = len;
 }
 
index 9b53b80..0290013 100644 (file)
@@ -2,14 +2,8 @@
  * http_client - HTTP client
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -98,7 +92,7 @@ static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
                   (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,
+       res = send(c->sd, wpabuf_head_u8(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",
index 924d6ab..ddee2ad 100644 (file)
@@ -2,14 +2,8 @@
  * http_client - HTTP client
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HTTP_CLIENT_H
index 356f599..6ca3214 100644 (file)
@@ -2,14 +2,8 @@
  * http_server - HTTP server
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 219941c..4b2b749 100644 (file)
@@ -2,14 +2,8 @@
  * http_server - HTTP server
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HTTP_SERVER_H
index 40422e4..ad4f4a1 100644 (file)
@@ -3,14 +3,8 @@
  * 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.
+ * 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
index 51aa214..454b618 100644 (file)
@@ -3,14 +3,8 @@
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HTTPREAD_H
index 9baec7f..96685d2 100644 (file)
@@ -1,34 +1,28 @@
 /*
  * 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@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@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.
+ * 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"
-#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_NFC_FORUM (0x01)
 #define FLAG_TNF_RFC2046 (0x02)
 
 struct ndef_record {
-       u8 *type;
-       u8 *id;
-       u8 *payload;
+       const u8 *type;
+       const u8 *id;
+       const u8 *payload;
        u8 type_length;
        u8 id_length;
        u32 payload_length;
@@ -37,9 +31,10 @@ struct ndef_record {
 
 static char wifi_handover_type[] = "application/vnd.wfa.wsc";
 
-static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
+static int ndef_parse_record(const u8 *data, u32 size,
+                            struct ndef_record *record)
 {
-       u8 *pos = data + 1;
+       const u8 *pos = data + 1;
 
        if (size < 2)
                return -1;
@@ -78,12 +73,12 @@ static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
 }
 
 
-static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
+static struct wpabuf * ndef_parse_records(const struct wpabuf *buf,
                                          int (*filter)(struct ndef_record *))
 {
        struct ndef_record record;
        int len = wpabuf_len(buf);
-       u8 *data = wpabuf_mhead(buf);
+       const u8 *data = wpabuf_head(buf);
 
        while (len > 0) {
                if (ndef_parse_record(data, len, &record) < 0) {
@@ -103,13 +98,14 @@ static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
 
 static struct wpabuf * ndef_build_record(u8 flags, void *type,
                                         u8 type_length, void *id,
-                                        u8 id_length, void *payload,
-                                        u32 payload_length)
+                                        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;
 
@@ -144,7 +140,7 @@ static struct wpabuf * ndef_build_record(u8 flags, void *type,
                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);
+       wpabuf_put_buf(record, payload);
        return record;
 }
 
@@ -160,16 +156,99 @@ static int wifi_filter(struct ndef_record *record)
 }
 
 
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf)
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf)
 {
        return ndef_parse_records(buf, wifi_filter);
 }
 
 
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
+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,
-                                wpabuf_mhead(buf), wpabuf_len(buf));
+                                os_strlen(wifi_handover_type), NULL, 0, buf);
+}
+
+
+struct wpabuf * ndef_build_wifi_hc(int begin)
+{
+       struct wpabuf *hc, *carrier;
+
+       carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+       if (carrier == NULL)
+               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((begin ? FLAG_MESSAGE_BEGIN : 0) |
+                              FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+                              "0", 1, carrier);
+       wpabuf_free(carrier);
+
+       return hc;
+}
+
+
+struct wpabuf * ndef_build_wifi_hr(void)
+{
+       struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
+       struct wpabuf *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;
+
+       hc = ndef_build_wifi_hc(0);
+       if (hc == NULL) {
+               wpabuf_free(hr);
+               return NULL;
+       }
+
+       return wpabuf_concat(hr, hc);
 }
index 2ba3d4b..ff4b20d 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -51,8 +45,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                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 ?
-                       cfg->dev_pw_id : data->wps->oob_dev_pw_id;
+               data->dev_pw_id = cfg->dev_pw_id;
                data->dev_password = os_malloc(cfg->pin_len);
                if (data->dev_password == NULL) {
                        os_free(data);
@@ -60,7 +53,32 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                }
                os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
                data->dev_password_len = cfg->pin_len;
+               wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
+                               data->dev_password, data->dev_password_len);
+       }
+
+#ifdef CONFIG_WPS_NFC
+       if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+               /* Keep AP PIN as alternative Device Password */
+               data->alt_dev_pw_id = data->dev_pw_id;
+               data->alt_dev_password = data->dev_password;
+               data->alt_dev_password_len = data->dev_password_len;
+
+               data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
+               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);
+               wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
+                           data->dev_password, data->dev_password_len);
        }
+#endif /* CONFIG_WPS_NFC */
 
        data->pbc = cfg->pbc;
        if (cfg->pbc) {
@@ -99,6 +117,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                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;
                }
@@ -124,6 +143,12 @@ struct wps_data * wps_init(const struct wps_config *cfg)
  */
 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");
@@ -138,10 +163,12 @@ void wps_deinit(struct wps_data *data)
        wpabuf_free(data->dh_pubkey_r);
        wpabuf_free(data->last_msg);
        os_free(data->dev_password);
+       os_free(data->alt_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);
 }
 
@@ -269,7 +296,8 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
  * @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: 1 if address is authorized, 0 if not
+ * 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)
@@ -295,8 +323,9 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
 
        pos = attr.authorized_macs;
        for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
-               if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
-                   os_memcmp(pos, bcast, ETH_ALEN) == 0)
+               if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+                       return 2;
+               if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
                        return 1;
                pos += ETH_ALEN;
        }
@@ -437,7 +466,8 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
 
 /**
  * wps_build_probe_req_ie - Build WPS IE for Probe Request
- * @pbc: Whether searching for PBC mode APs
+ * @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
@@ -448,7 +478,7 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
  *
  * The caller is responsible for freeing the buffer.
  */
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+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,
@@ -470,8 +500,7 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
            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) ||
+           wps_build_dev_password_id(ie, pw_id) ||
 #ifdef CONFIG_WPS2
            wps_build_manufacturer(dev, ie) ||
            wps_build_model_name(dev, ie) ||
index 4986881..cb03dbd 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPS_H
@@ -33,6 +27,7 @@ enum wsc_op_code {
 struct wps_registrar;
 struct upnp_wps_device_sm;
 struct wps_er;
+struct wps_parse_attr;
 
 /**
  * struct wps_credential - WPS Credential
@@ -47,6 +42,7 @@ struct wps_er;
  * @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];
@@ -59,6 +55,7 @@ struct wps_credential {
        u8 mac_addr[ETH_ALEN];
        const u8 *cred_attr;
        size_t cred_attr_len;
+       u16 ap_channel;
 };
 
 #define WPS_DEV_TYPE_LEN 8
@@ -100,22 +97,12 @@ struct wps_device_data {
        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 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
  */
@@ -244,7 +231,7 @@ 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(int pbc, struct wps_device_data *dev,
+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,
@@ -300,12 +287,15 @@ struct wps_registrar_config {
         * @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 *uuid_e, const u8 *dev_pw,
+                              size_t dev_pw_len);
 
        /**
         * set_sel_reg_cb - Callback for reporting selected registrar changes
@@ -457,7 +447,12 @@ enum wps_event {
        /**
         * WPS_EV_ER_SET_SELECTED_REGISTRAR - ER: SetSelectedRegistrar event
         */
-       WPS_EV_ER_SET_SELECTED_REGISTRAR
+       WPS_EV_ER_SET_SELECTED_REGISTRAR,
+
+       /**
+        * WPS_EV_AP_PIN_SUCCESS - External Registrar used correct AP PIN
+        */
+       WPS_EV_AP_PIN_SUCCESS
 };
 
 /**
@@ -613,16 +608,6 @@ struct wps_context {
        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;
@@ -753,23 +738,11 @@ struct wps_context {
 
        /* 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);
+       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 *
@@ -784,7 +757,8 @@ 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);
+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);
@@ -793,6 +767,12 @@ 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);
@@ -800,13 +780,11 @@ int wps_build_credential_wrap(struct wpabuf *msg,
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
 unsigned int wps_generate_pin(void);
+int wps_pin_str_valid(const char *pin);
 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);
+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,
@@ -815,19 +793,39 @@ 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,
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr);
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+                const u8 *pin, size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
                      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);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+                 const u8 *pin, size_t pin_len,
+                 const struct wps_credential *cred);
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+                                             struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+                                       const u8 *addr);
 
 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_build(int ndef, int id, struct wpabuf *pubkey,
+                                   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_hc(int begin);
+struct wpabuf * ndef_build_wifi_hr(void);
 
 #ifdef CONFIG_WPS_STRICT
 int wps_validate_beacon(const struct wpabuf *wps_ie);
index d2ca31a..ac9bb1e 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - attribute building
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -30,15 +24,39 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 
        wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
        wpabuf_free(wps->dh_privkey);
-       if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+       wps->dh_privkey = NULL;
+       if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
+           wps->wps->dh_ctx) {
                wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+               if (wps->wps->dh_pubkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->dh_pubkey == NULL");
+                       return -1;
+               }
                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");
+               if (wps->wps->ap_nfc_dh_privkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
+                       return -1;
+               }
+               if (wps->wps->ap_nfc_dh_pubkey == NULL) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
+                       return -1;
+               }
+               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);
@@ -346,44 +364,23 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
 
 
 #ifdef CONFIG_WPS_OOB
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+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];
-       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);
+       addr[0] = wpabuf_head(pubkey);
+       hash_len = wpabuf_len(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 (random_get_bytes(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_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, 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);
+       wpabuf_put_be16(msg, dev_pw_id);
+       wpabuf_put_data(msg, dev_pw, dev_pw_len);
 
        return 0;
 }
@@ -420,3 +417,14 @@ struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
 
        return ie;
 }
+
+
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
+{
+       wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
+                  MAC2STR(addr));
+       wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+       wpabuf_put_be16(msg, ETH_ALEN);
+       wpabuf_put_data(msg, addr, ETH_ALEN);
+       return 0;
+}
index 55b5573..3999b1b 100644 (file)
@@ -2,20 +2,15 @@
  * Wi-Fi Protected Setup - attribute parsing
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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_defs.h"
+#include "wps_attr_parse.h"
 
 #ifndef CONFIG_WPS_STRICT
 #define WPS_WORKAROUNDS
@@ -268,12 +263,16 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
                attr->dev_password_id = pos;
                break;
        case ATTR_OOB_DEVICE_PASSWORD:
-               if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
+               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) {
@@ -543,6 +542,14 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
                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);
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
new file mode 100644 (file)
index 0000000..88e51a4
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008-2012, Jouni Malinen <j@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 */
index 07e087d..b81f106 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - attribute processing
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -264,6 +258,19 @@ static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
 }
 
 
+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) &&
@@ -309,7 +316,8 @@ int wps_process_cred(struct wps_parse_attr *attr,
            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_802_1x_enabled(cred, attr->dot1x_enabled) ||
+           wps_process_cred_ap_channel(cred, attr->ap_channel))
                return -1;
 
        return wps_workaround_cred_key(cred);
index 505837b..4e4da5e 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Wi-Fi Protected Setup - common functionality
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -255,6 +249,22 @@ unsigned int wps_generate_pin(void)
 }
 
 
+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)
 {
@@ -314,7 +324,7 @@ void wps_pbc_timeout_event(struct wps_context *wps)
 
 #ifdef CONFIG_WPS_OOB
 
-static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
 {
        struct wps_data data;
        struct wpabuf *plain;
@@ -333,40 +343,56 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
        if (wps_build_version(plain) ||
            wps_build_cred(&data, plain) ||
            wps_build_wfa_ext(plain, 0, NULL, 0)) {
+               os_free(data.new_psk);
                wpabuf_free(plain);
                return NULL;
        }
 
+       if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
+           wps->ap) {
+               struct wps_credential cred;
+
+               wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+                          "on credential token generation");
+
+               os_memset(&cred, 0, sizeof(cred));
+               os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
+               cred.ssid_len = 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, data.new_psk, data.new_psk_len);
+               cred.key_len = data.new_psk_len;
+
+               wps->wps_state = WPS_STATE_CONFIGURED;
+               wpa_hexdump_ascii_key(MSG_DEBUG,
+                                     "WPS: Generated random passphrase",
+                                     data.new_psk, data.new_psk_len);
+               if (wps->cred_cb)
+                       wps->cred_cb(wps->cb_ctx, &cred);
+       }
+
+       os_free(data.new_psk);
+
        return plain;
 }
 
 
-static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
+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(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
-       if (data == NULL) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-                          "device password attribute");
+       data = wpabuf_alloc(200);
+       if (data == NULL)
                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) ||
+           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: Build OOB device password "
-                          "attribute error");
+               wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
+                          "token");
                wpabuf_free(data);
                return NULL;
        }
@@ -375,66 +401,17 @@ static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
 }
 
 
-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)
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
 {
        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++) {
+       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]);
+               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 "
@@ -448,94 +425,6 @@ static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
 }
 
 
-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 */
 
 
@@ -615,15 +504,10 @@ u16 wps_config_methods_str2bin(const char *str)
 #ifdef CONFIG_WPS2
                methods |= WPS_CONFIG_VIRT_DISPLAY;
 #endif /* CONFIG_WPS2 */
-#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"))
@@ -701,3 +585,67 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
 
        return msg;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+                                   struct wpabuf *dev_pw)
+{
+       struct wpabuf *ret;
+
+       if (pubkey == NULL || dev_pw == NULL)
+               return NULL;
+
+       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;
+}
+
+
+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;
+       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;
+
+       return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
+}
+
+#endif /* CONFIG_WPS_NFC */
index 43311f3..2f42603 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - message definitions
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPS_DEFS_H
@@ -47,7 +41,7 @@ extern int wps_testing_dummy_cred;
 #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_MIN_LEN 16
 #define WPS_OOB_DEVICE_PASSWORD_LEN 32
 #define WPS_OOB_PUBKEY_HASH_LEN 20
 
index f2fb03a..7a7c099 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - device attributes
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -209,6 +203,20 @@ 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)
+{
+       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);
@@ -249,11 +257,9 @@ static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
 
        os_free(dev->manufacturer);
-       dev->manufacturer = os_malloc(str_len + 1);
+       dev->manufacturer = dup_binstr(str, str_len);
        if (dev->manufacturer == NULL)
                return -1;
-       os_memcpy(dev->manufacturer, str, str_len);
-       dev->manufacturer[str_len] = '\0';
 
        return 0;
 }
@@ -270,11 +276,9 @@ static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
 
        os_free(dev->model_name);
-       dev->model_name = os_malloc(str_len + 1);
+       dev->model_name = dup_binstr(str, str_len);
        if (dev->model_name == NULL)
                return -1;
-       os_memcpy(dev->model_name, str, str_len);
-       dev->model_name[str_len] = '\0';
 
        return 0;
 }
@@ -291,11 +295,9 @@ static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
 
        os_free(dev->model_number);
-       dev->model_number = os_malloc(str_len + 1);
+       dev->model_number = dup_binstr(str, str_len);
        if (dev->model_number == NULL)
                return -1;
-       os_memcpy(dev->model_number, str, str_len);
-       dev->model_number[str_len] = '\0';
 
        return 0;
 }
@@ -312,11 +314,9 @@ static int wps_process_serial_number(struct wps_device_data *dev,
        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
 
        os_free(dev->serial_number);
-       dev->serial_number = os_malloc(str_len + 1);
+       dev->serial_number = dup_binstr(str, str_len);
        if (dev->serial_number == NULL)
                return -1;
-       os_memcpy(dev->serial_number, str, str_len);
-       dev->serial_number[str_len] = '\0';
 
        return 0;
 }
@@ -333,11 +333,9 @@ static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
 
        os_free(dev->device_name);
-       dev->device_name = os_malloc(str_len + 1);
+       dev->device_name = dup_binstr(str, str_len);
        if (dev->device_name == NULL)
                return -1;
-       os_memcpy(dev->device_name, str, str_len);
-       dev->device_name[str_len] = '\0';
 
        return 0;
 }
index f26a05b..200c9c4 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - device attributes
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPS_DEV_ATTR_H
@@ -23,6 +17,7 @@ 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);
index 0fbaa3f..27c554f 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - Enrollee
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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;
@@ -155,7 +139,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
        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_mac_addr(msg, wps->mac_addr_e) ||
            wps_build_enrollee_nonce(wps, msg) ||
            wps_build_public_key(wps, msg) ||
            wps_build_auth_type_flags(wps, msg) ||
@@ -169,7 +153,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
            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_wfa_ext(msg, 0, NULL, 0) ||
+           wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
                wpabuf_free(msg);
                return NULL;
        }
@@ -257,20 +242,47 @@ static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
 
 static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
 {
-       wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type");
+       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, wps->wps->auth_types);
+       wpabuf_put_be16(msg, auth_type);
        return 0;
 }
 
 
 static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
 {
-       wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type");
+       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, wps->wps->encr_types);
+       wpabuf_put_be16(msg, encr_type);
        return 0;
 }
 
@@ -501,23 +513,6 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
                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)
@@ -643,6 +638,7 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 {
        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));
@@ -692,12 +688,12 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
        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);
+               ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
                wps->cred.cred_attr = NULL;
                wps->cred.cred_attr_len = 0;
        }
 
-       return 0;
+       return ret;
 }
 
 
@@ -831,6 +827,57 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
 }
 
 
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+       u16 id;
+
+       if (dev_pw_id == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+               return -1;
+       }
+
+       id = WPA_GET_BE16(dev_pw_id);
+       if (wps->dev_pw_id == id) {
+               wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+               return 0;
+       }
+
+#ifdef CONFIG_P2P
+       if ((id == DEV_PW_DEFAULT &&
+            wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) ||
+           (id == DEV_PW_REGISTRAR_SPECIFIED &&
+            wps->dev_pw_id == DEV_PW_DEFAULT)) {
+               /*
+                * Common P2P use cases indicate whether the PIN is from the
+                * client or GO using Device Password Id in M1/M2 in a way that
+                * does not look fully compliant with WSC specification. Anyway,
+                * this is deployed and needs to be allowed, so ignore changes
+                * between Registrar-Specified and Default PIN.
+                */
+               wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID "
+                          "change");
+               return 0;
+       }
+#endif /* CONFIG_P2P */
+
+       wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+                  "ID from %u to %u", wps->dev_pw_id, id);
+
+       if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+               wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+               os_free(wps->dev_password);
+               wps->dev_pw_id = wps->alt_dev_pw_id;
+               wps->dev_password = wps->alt_dev_password;
+               wps->dev_password_len = wps->alt_dev_password_len;
+               wps->alt_dev_password = NULL;
+               wps->alt_dev_password_len = 0;
+               return 0;
+       }
+
+       return -1;
+}
+
+
 static enum wps_process_res wps_process_m2(struct wps_data *wps,
                                           const struct wpabuf *msg,
                                           struct wps_parse_attr *attr)
@@ -846,7 +893,8 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
 
        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_process_uuid_r(wps, attr->uuid_r) ||
+           wps_process_dev_pw_id(wps, attr->dev_password_id)) {
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -1037,6 +1085,10 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
        }
        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;
 }
@@ -1124,7 +1176,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
                return WPS_FAILURE;
 
        if (attr.enrollee_nonce == NULL ||
-           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
                return WPS_FAILURE;
        }
@@ -1216,14 +1268,14 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
        }
 
        if (attr.registrar_nonce == NULL ||
-           os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+           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)) {
+           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
                return WPS_FAILURE;
        }
@@ -1263,7 +1315,7 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
        }
 
        if (attr.registrar_nonce == NULL ||
-           os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+           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",
@@ -1274,7 +1326,7 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
        }
 
        if (attr.enrollee_nonce == NULL ||
-           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+           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);
index 856e9fb..5694997 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -103,13 +97,16 @@ static void wps_er_sta_remove_all(struct wps_er_ap *ap)
 
 
 static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
-                                       struct in_addr *addr, const u8 *uuid)
+                                       struct in_addr *addr, const u8 *uuid,
+                                       const u8 *mac_addr)
 {
        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))
+                    os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
+                   (mac_addr == NULL ||
+                    os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
                        return ap;
        }
        return NULL;
@@ -296,7 +293,7 @@ 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);
+       ap = wps_er_ap_get(er, addr, NULL, NULL);
        if (ap == NULL || ap->ap_settings == NULL)
                return -1;
 
@@ -642,7 +639,7 @@ void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
 {
        struct wps_er_ap *ap;
 
-       ap = wps_er_ap_get(er, addr, uuid);
+       ap = wps_er_ap_get(er, addr, uuid, NULL);
        if (ap) {
                /* Update advertisement timeout */
                eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
@@ -799,52 +796,31 @@ static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
 
        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';
-               }
+               sta->manufacturer = dup_binstr(attr->manufacturer,
+                                              attr->manufacturer_len);
        }
 
        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';
-               }
+               sta->model_name = dup_binstr(attr->model_name,
+                                            attr->model_name_len);
        }
 
        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';
-               }
+               sta->model_number = dup_binstr(attr->model_number,
+                                              attr->model_number_len);
        }
 
        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';
-               }
+               sta->serial_number = dup_binstr(attr->serial_number,
+                                               attr->serial_number_len);
        }
 
        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';
-               }
+               sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
        }
 
        eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
@@ -1295,6 +1271,22 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
        /* Limit event_id to < 32 bits to avoid issues with atoi() */
        er->event_id &= 0x0fffffff;
 
+       if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
+               const char *pos, *end;
+               pos = filter + 7;
+               end = os_strchr(pos, ' ');
+               if (end) {
+                       size_t len = end - pos;
+                       os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
+                                  len + 1 : sizeof(er->ifname));
+                       filter = end + 1;
+               } else {
+                       os_strlcpy(er->ifname, pos, sizeof(er->ifname));
+                       filter = NULL;
+               }
+               er->forced_ifname = 1;
+       }
+
        if (filter) {
                if (inet_aton(filter, &er->filter_addr) == 0) {
                        wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
@@ -1305,10 +1297,10 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
                wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
                           "with %s", filter);
        }
-       if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
+       if (get_netif_info(er->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);
+                          "for %s. Does it have IP address?", er->ifname);
                wps_er_deinit(er, NULL, NULL);
                return NULL;
        }
@@ -1561,7 +1553,7 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
 }
 
 
-int wps_er_pbc(struct wps_er *er, const u8 *uuid)
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
 {
        int res;
        struct wps_er_ap *ap;
@@ -1575,11 +1567,14 @@ int wps_er_pbc(struct wps_er *er, const u8 *uuid)
                return -2;
        }
 
-       ap = wps_er_ap_get(er, NULL, uuid);
+       if (uuid)
+               ap = wps_er_ap_get(er, NULL, uuid, NULL);
+       else
+               ap = NULL;
        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);
+                       sta = wps_er_sta_get(ap, addr, uuid);
                        if (sta) {
                                uuid = ap->uuid;
                                break;
@@ -1625,6 +1620,19 @@ static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
 }
 
 
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
+{
+       struct wps_er_ap *ap;
+       dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+               struct wps_er_sta *sta;
+               sta = wps_er_sta_get(ap, addr, NULL);
+               if (sta)
+                       return sta->uuid;
+       }
+       return NULL;
+}
+
+
 static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
                                       enum http_client_event event)
 {
@@ -1883,20 +1891,22 @@ static int wps_er_send_get_device_info(struct wps_er_ap *ap,
 }
 
 
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-                size_t pin_len)
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+                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);
+       ap = wps_er_ap_get(er, NULL, uuid, addr);
        if (ap == NULL) {
                wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
                           "request");
                return -1;
        }
+       if (uuid == NULL)
+               uuid = ap->uuid;
        if (ap->wps) {
                wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
                           "with the AP - cannot start learn");
@@ -1914,7 +1924,7 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
 }
 
 
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
                      const struct wps_credential *cred)
 {
        struct wps_er_ap *ap;
@@ -1922,7 +1932,7 @@ int wps_er_set_config(struct wps_er *er, const u8 *uuid,
        if (er == NULL)
                return -1;
 
-       ap = wps_er_ap_get(er, NULL, uuid);
+       ap = wps_er_ap_get(er, NULL, uuid, addr);
        if (ap == NULL) {
                wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
                           "request");
@@ -1966,20 +1976,23 @@ static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
 }
 
 
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
-                 size_t pin_len, const struct wps_credential *cred)
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+                 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);
+       ap = wps_er_ap_get(er, NULL, uuid, addr);
        if (ap == NULL) {
                wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
                           "request");
                return -1;
        }
+       if (uuid == NULL)
+               uuid = ap->uuid;
        if (ap->wps) {
                wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
                           "with the AP - cannot start config");
@@ -2002,3 +2015,52 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
 
        return 0;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+                                             struct wps_credential *cred)
+{
+       struct wpabuf *ret;
+       struct wps_data data;
+
+       ret = wpabuf_alloc(500);
+       if (ret == NULL)
+               return NULL;
+
+       os_memset(&data, 0, sizeof(data));
+       data.wps = wps;
+       data.use_cred = cred;
+       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;
+}
+
+
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+                                       const u8 *addr)
+{
+       struct wps_er_ap *ap;
+
+       if (er == NULL)
+               return NULL;
+
+       ap = wps_er_ap_get(er, NULL, uuid, addr);
+       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;
+       }
+
+       return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
+}
+
+#endif /* CONFIG_WPS_NFC */
index 5388ed1..4b48ff6 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - External Registrar
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPS_ER_H
@@ -82,6 +76,7 @@ struct wps_er_ap_settings {
 struct wps_er {
        struct wps_context *wps;
        char ifname[17];
+       int forced_ifname;
        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) */
index 83de9ad..e381fec 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - External Registrar (SSDP)
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -172,7 +166,9 @@ int wps_er_ssdp_init(struct wps_er *er)
                return -1;
        }
 
-       er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+       er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr,
+                                                   er->forced_ifname ?
+                                                   er->ifname : NULL);
        if (er->multicast_sd < 0) {
                wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
                           "for SSDP");
index bdb6da2..413379b 100644 (file)
@@ -1,21 +1,18 @@
 /*
  * Wi-Fi Protected Setup - internal definitions
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -74,6 +71,9 @@ struct wps_data {
        size_t dev_password_len;
        u16 dev_pw_id;
        int pbc;
+       u8 *alt_dev_password;
+       size_t alt_dev_password_len;
+       u16 alt_dev_pw_id;
 
        /**
         * request_type - Request Type attribute from (Re)AssocReq
@@ -120,100 +120,11 @@ struct wps_data {
        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_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 *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 */
-       const u8 *settings_delay_time; /* 1 octet */
-       const u8 *network_key_shareable; /* 1 octet (Bool) */
-       const u8 *request_to_enroll; /* 1 octet (Bool) */
-
-       /* 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;
-
-       /* 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;
+       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);
@@ -229,16 +140,9 @@ 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;
-
 struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
 struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
 
-/* 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);
@@ -261,8 +165,11 @@ 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);
+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);
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr);
 
 /* wps_attr_process.c */
 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
@@ -290,13 +197,12 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
 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);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+                                             u16 dev_pw_id);
 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);
-
-/* ndef.c */
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf);
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+                                      struct wps_nfc_pw_token *token);
 
 #endif /* WPS_I_H */
diff --git a/src/wps/wps_nfc.c b/src/wps/wps_nfc.c
deleted file mode 100644 (file)
index ff12000..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@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,
-};
diff --git a/src/wps/wps_nfc_pn531.c b/src/wps/wps_nfc_pn531.c
deleted file mode 100644 (file)
index 7e05e4d..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@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,
-};
index eda1c70..4812893 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #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 * 2 + 1];
+       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];
@@ -108,7 +149,8 @@ struct wps_registrar {
        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 *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,
@@ -118,6 +160,7 @@ struct wps_registrar {
        void *cb_ctx;
 
        struct dl_list pins;
+       struct dl_list nfc_pw_tokens;
        struct wps_pbc_session *pbc_sessions;
 
        int skip_cred_build;
@@ -137,6 +180,9 @@ struct wps_registrar {
        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;
 };
 
 
@@ -144,6 +190,8 @@ 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,
@@ -485,12 +533,16 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
 {
        *methods |= WPS_CONFIG_PUSHBUTTON;
 #ifdef CONFIG_WPS2
-       if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON)
+       if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
+           WPS_CONFIG_VIRT_PUSHBUTTON)
                *methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
-       if (conf_methods & WPS_CONFIG_PHY_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_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
@@ -592,6 +644,7 @@ wps_registrar_init(struct wps_context *wps,
                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;
@@ -635,6 +688,7 @@ void wps_registrar_deinit(struct wps_registrar *reg)
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        wps_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);
@@ -642,6 +696,21 @@ void wps_registrar_deinit(struct wps_registrar *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()
@@ -681,6 +750,9 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
                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)",
@@ -694,7 +766,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
        else
                wps_registrar_add_authorized_mac(
                        reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
-       wps_registrar_selected_registrar_changed(reg);
+       wps_registrar_selected_registrar_changed(reg, 0);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
                               wps_registrar_set_selected_timeout,
@@ -716,7 +788,7 @@ static void wps_registrar_remove_pin(struct wps_registrar *reg,
                addr = pin->enrollee_addr;
        wps_registrar_remove_authorized_mac(reg, addr);
        wps_remove_pin(pin);
-       wps_registrar_selected_registrar_changed(reg);
+       wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -741,14 +813,22 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
 /**
  * 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)
+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);
@@ -804,10 +884,11 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
                /* 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) {
+                       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 = 2;
+                               pin->wildcard_uuid++;
                                os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
                                found = pin;
                                break;
@@ -849,7 +930,7 @@ int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
 
        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) {
+                       if (pin->wildcard_uuid == 3) {
                                wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
                                           "wildcard PIN");
                                return wps_registrar_invalidate_pin(reg, uuid);
@@ -870,7 +951,7 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg)
        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);
+       wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -918,7 +999,7 @@ int wps_registrar_button_pushed(struct wps_registrar *reg,
                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);
+       wps_registrar_selected_registrar_changed(reg, 0);
 
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
@@ -941,19 +1022,29 @@ 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_selected_registrar_changed(reg, 0);
 }
 
 
-void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+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);
+       }
 }
 
 
@@ -962,12 +1053,13 @@ 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);
+               wps_registrar_invalidate_wildcard_pin(reg, NULL, 0);
                return 1;
        }
        return 0;
@@ -989,6 +1081,7 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                                int p2p_wildcard)
 {
        struct wps_parse_attr attr;
+       int skip_add = 0;
 
        wpa_hexdump_buf(MSG_MSGDUMP,
                        "WPS: Probe Request with WPS data received",
@@ -1040,7 +1133,24 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
        wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
                    WPS_UUID_LEN);
 
-       wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+#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;
@@ -1070,12 +1180,13 @@ static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
 
 
 static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
-                              const u8 *uuid_e)
+                              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);
+       reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len);
 }
 
 
@@ -1182,7 +1293,7 @@ static int wps_set_ie(struct wps_registrar *reg)
            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) ||
+           (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);
@@ -1237,9 +1348,24 @@ static int wps_get_dev_password(struct wps_data *wps)
                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 && wps->dev_pw_id >= 0x10) {
+                       wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+                                  "Password ID, but PIN found");
+                       /*
+                        * See whether Enrollee is willing to use PIN instead.
+                        */
+                       wps->dev_pw_id = DEV_PW_DEFAULT;
+               }
        }
        if (pin == NULL) {
                wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
@@ -1400,18 +1526,6 @@ static int wps_build_cred_network_key(struct wpabuf *msg,
 }
 
 
-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)
 {
@@ -1420,7 +1534,7 @@ static int wps_build_credential(struct wpabuf *msg,
            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))
+           wps_build_mac_addr(msg, cred->mac_addr))
                return -1;
        return 0;
 }
@@ -2103,6 +2217,13 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
        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;
 }
 
@@ -2131,22 +2252,6 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
                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)
@@ -2416,15 +2521,31 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
                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;
+#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_OOB */
+#endif /* CONFIG_WPS_NFC */
 
        if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
                if ((wps->wps->registrar->force_pbc_overlap ||
@@ -2741,7 +2862,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
        if (*attr.msg_type != WPS_M1 &&
            (attr.registrar_nonce == NULL ||
             os_memcmp(wps->nonce_r, attr.registrar_nonce,
-                      WPS_NONCE_LEN != 0))) {
+                      WPS_NONCE_LEN) != 0)) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
                return WPS_FAILURE;
        }
@@ -2837,14 +2958,14 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
 #endif /* CONFIG_WPS_UPNP */
 
        if (attr.registrar_nonce == NULL ||
-           os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+           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)) {
+           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
                return WPS_FAILURE;
        }
@@ -2906,14 +3027,14 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
 #endif /* CONFIG_WPS_UPNP */
 
        if (attr.registrar_nonce == NULL ||
-           os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+           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)) {
+           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
                return WPS_FAILURE;
        }
@@ -2992,14 +3113,14 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
 #endif /* CONFIG_WPS_UPNP */
 
        if (attr.registrar_nonce == NULL ||
-           os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+           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)) {
+           os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
                wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
                return WPS_FAILURE;
        }
@@ -3047,13 +3168,17 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
                wps->new_psk = NULL;
        }
 
-       wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
+       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);
        }
@@ -3154,7 +3279,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
                   "unselect internal Registrar");
        reg->selected_registrar = 0;
        reg->pbc = 0;
-       wps_registrar_selected_registrar_changed(reg);
+       wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -3226,7 +3351,8 @@ static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
  * 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)
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+                                             u16 dev_pw_id)
 {
        wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
 
@@ -3250,7 +3376,8 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
                        reg->sel_reg_dev_password_id_override =
                                DEV_PW_PUSHBUTTON;
                        wps_set_pushbutton(&methods, reg->wps->config_methods);
-               }
+               } else if (dev_pw_id)
+                       reg->sel_reg_dev_password_id_override = dev_pw_id;
                wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
                           "(pbc=%d)", reg->pbc);
                reg->sel_reg_config_methods_override = methods;
@@ -3340,3 +3467,89 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
 
        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;
+       wpa_snprintf_hex_uppercase((char *) token->dev_pw,
+                                  sizeof(token->dev_pw),
+                                  dev_pw, dev_pw_len);
+       token->dev_pw_len = dev_pw_len * 2;
+
+       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, pw_id);
+       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);
+
+       wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar",
+                  pw_id);
+
+       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, 0);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
deleted file mode 100644 (file)
index 61f6553..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@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 <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,
-};
index 06dcd20..af63e4d 100644 (file)
@@ -305,15 +305,15 @@ 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 *host;
        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;
+       size_t host_len, path_len;
 
        /* url MUST begin with http: */
        if (url_len < 7 || os_strncasecmp(url, "http://", 7))
@@ -321,30 +321,22 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
        url += 7;
        url_len -= 7;
 
-       /* allocate memory for the extra stuff we need */
-       alloc_len = 2 * (url_len + 1);
-       scratch_mem = os_zalloc(alloc_len);
+       /* Make a copy of the string to allow modification during parsing */
+       scratch_mem = dup_binstr(url, url_len);
        if (scratch_mem == NULL)
                goto fail;
-       mem = scratch_mem;
-       os_strncpy(mem, url, url_len);
-       wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem);
-       domain_and_port = mem;
-       mem += 1 + os_strlen(mem);
-       delim = os_strchr(domain_and_port, '/');
+       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 domain and port */
-               path = delim;
-       } else {
-               path = domain_and_port + os_strlen(domain_and_port);
-       }
-       domain = mem;
-       strcpy(domain, domain_and_port);
-       delim = os_strchr(domain, ':');
-       if (delim) {
-               *delim++ = 0;   /* null terminate domain */
-               if (isdigit(*delim))
-                       port = atol(delim);
+               *delim = '\0'; /* null terminate host name for now */
+               if (isdigit(delim[1]))
+                       port = atol(delim + 1);
        }
 
        /*
@@ -367,13 +359,21 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
        hints.ai_flags = 0;
 #endif
        hints.ai_protocol = 0;          /* Any protocol? */
-       rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
+       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), domain);
+                          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;
 
@@ -386,16 +386,16 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
 
                a = os_zalloc(sizeof(*a) + alloc_len);
                if (a == NULL)
-                       continue;
-               mem = (void *) (a + 1);
+                       break;
+               mem = (char *) (a + 1);
                a->domain_and_port = mem;
-               strcpy(mem, domain_and_port);
-               mem += 1 + strlen(mem);
+               os_memcpy(mem, host, host_len);
+               mem += host_len + 1;
                a->path = mem;
-               if (path[0] != '/')
+               if (path == NULL || path[0] != '/')
                        *mem++ = '/';
-               strcpy(mem, path);
-               mem += 1 + os_strlen(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);
 
@@ -550,10 +550,13 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
  */
 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);
-       upnp_er_remove_notification(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);
 }
 
index 501ecbc..4f1dd8f 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - UPnP AP functionality
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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(s->reg);
+       wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -46,7 +41,7 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
                return -1;
 
        s->reg = reg;
-       eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
+       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) {
@@ -73,19 +68,20 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
 #endif /* CONFIG_WPS2 */
                }
                eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
-                                      upnp_er_set_selected_timeout, s, NULL);
+                                      upnp_er_set_selected_timeout, s, reg);
        }
 
-       wps_registrar_selected_registrar_changed(reg);
+       wps_registrar_selected_registrar_changed(reg, 0);
 
        return 0;
 }
 
 
-void upnp_er_remove_notification(struct subscription *s)
+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, NULL);
-       if (s->reg)
-               wps_registrar_selected_registrar_changed(s->reg);
+       eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
+       if (reg)
+               wps_registrar_selected_registrar_changed(reg, 0);
 }
index 3ecf05d..5c39f7e 100644 (file)
@@ -171,7 +171,7 @@ 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_sock(u32 ip_addr, const char *forced_ifname);
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
 
 /* wps_upnp_web.c */
@@ -188,6 +188,7 @@ void event_send_stop_all(struct upnp_wps_device_sm *sm);
 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);
+void upnp_er_remove_notification(struct wps_registrar *reg,
+                                struct subscription *s);
 
 #endif /* WPS_UPNP_I_H */
index 4c4aebf..416961c 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2000-2003 Intel Corporation
  * Copyright (c) 2006-2007 Sony Corporation
  * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * See wps_upnp.c for more details on licensing and code history.
  */
@@ -13,6 +13,9 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <net/route.h>
+#ifdef __linux__
+#include <net/if.h>
+#endif /* __linux__ */
 
 #include "common.h"
 #include "uuid.h"
@@ -854,7 +857,7 @@ fail:
 }
 
 
-int ssdp_open_multicast_sock(u32 ip_addr)
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname)
 {
        int sd;
         /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
@@ -865,21 +868,41 @@ int ssdp_open_multicast_sock(u32 ip_addr)
        if (sd < 0)
                return -1;
 
+       if (forced_ifname) {
+#ifdef __linux__
+               struct ifreq req;
+               os_memset(&req, 0, sizeof(req));
+               os_strlcpy(req.ifr_name, forced_ifname, sizeof(req.ifr_name));
+               if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &req,
+                              sizeof(req)) < 0) {
+                       wpa_printf(MSG_INFO, "WPS UPnP: Failed to bind "
+                                  "multicast socket to ifname %s: %s",
+                                  forced_ifname, strerror(errno));
+                       close(sd);
+                       return -1;
+               }
+#endif /* __linux__ */
+       }
+
 #if 0   /* maybe ok if we sometimes block on writes */
-       if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+       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;
        }
 
@@ -898,6 +921,7 @@ int ssdp_open_multicast_sock(u32 ip_addr)
                                   "WPS UPnP: setsockopt "
                                   "IP_ADD_MEMBERSHIP errno %d (%s)",
                                   errno, strerror(errno));
+                       close(sd);
                        return -1;
                }
        }
@@ -919,7 +943,7 @@ int ssdp_open_multicast_sock(u32 ip_addr)
  */
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
 {
-       sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+       sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr, NULL);
        if (sm->multicast_sd < 0)
                return -1;
        return 0;
index ce0bede..11386d8 100644 (file)
@@ -996,13 +996,11 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
                                h++;
                        len = end - h;
                        os_free(callback_urls);
-                       callback_urls = os_malloc(len + 1);
+                       callback_urls = dup_binstr(h, len);
                        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 */
index c3071a0..e366256 100644 (file)
@@ -2,14 +2,8 @@
  * Wi-Fi Protected Setup - Strict protocol validation routines
  * Copyright (c) 2010, Atheros Communications, 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644 (file)
index 0000000..bef38cf
--- /dev/null
@@ -0,0 +1,15 @@
+test-aes
+test-asn1
+test-base64
+test-https
+test-list
+test-md4
+test-md5
+test-milenage
+test-ms_funcs
+test-printf
+test-rc4
+test-sha1
+test-sha256
+test-x509
+test-x509v3
index 91b10c5..80341a1 100644 (file)
@@ -1,4 +1,7 @@
-TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs test-sha1 \
+TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs \
+       test-bitfield \
+       test-printf \
+       test-sha1 \
        test-sha256 test-aes test-asn1 test-x509 test-x509v3 test-list test-rc4
 
 all: $(TESTS)
@@ -37,7 +40,7 @@ LLIBS = -Wl,--start-group $(DLIBS) -Wl,--end-group $(SLIBS)
 
 
 test-aes: test-aes.o $(LIBS)
-       $(LDO) $(LDFLAGS) -o $@ $^
+       $(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
 
 test-asn1: test-asn1.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
@@ -45,6 +48,9 @@ test-asn1: test-asn1.o $(LIBS)
 test-base64: test-base64.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
+test-bitfield: test-bitfield.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
 test-https: test-https.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
 
@@ -55,7 +61,7 @@ test-md4: test-md4.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
 test-md5: test-md5.o $(LIBS)
-       $(LDO) $(LDFLAGS) -o $@ $^
+       $(LDO) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 test-milenage: test-milenage.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
@@ -63,11 +69,14 @@ test-milenage: test-milenage.o $(LIBS)
 test-ms_funcs: test-ms_funcs.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
+test-printf: test-printf.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
 test-rc4: test-rc4.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
 test-sha1: test-sha1.o $(LIBS)
-       $(LDO) $(LDFLAGS) -o $@ $^
+       $(LDO) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 test-sha256: test-sha256.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
@@ -81,10 +90,12 @@ test-x509v3: test-x509v3.o $(LIBS)
 
 run-tests: $(TESTS)
        ./test-aes
+       ./test-bitfield
        ./test-list
        ./test-md4
        ./test-md5
        ./test-milenage
+       ./test-printf
        ./test-sha1
        ./test-sha256
        @echo
@@ -93,6 +104,7 @@ run-tests: $(TESTS)
 clean:
        $(MAKE) -C ../src clean
        rm -f $(TESTS) *~ *.o *.d
+       rm -f test-https
        rm -f test_x509v3_nist.out.*
        rm -f test_x509v3_nist2.out.*
 
diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py
new file mode 100644 (file)
index 0000000..464f026
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+#
+# Python class for controlling hostapd
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import time
+import logging
+import wpaspy
+
+logger = logging.getLogger(__name__)
+hapd_ctrl = '/var/run/hostapd'
+hapd_global = '/var/run/hostapd-global'
+
+class HostapdGlobal:
+    def __init__(self):
+        self.ctrl = wpaspy.Ctrl(hapd_global)
+
+    def add(self, ifname):
+        res = self.ctrl.request("ADD " + ifname + " " + hapd_ctrl)
+        if not "OK" in res:
+            raise Exception("Could not add hostapd interface " + ifname)
+
+    def remove(self, ifname):
+        self.ctrl.request("REMOVE " + ifname)
+
+
+class Hostapd:
+    def __init__(self, ifname):
+        self.ifname = ifname
+        self.ctrl = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
+
+    def request(self, cmd):
+        logger.debug(self.ifname + ": CTRL: " + cmd)
+        return self.ctrl.request(cmd)
+
+    def ping(self):
+        return "PONG" in self.request("PING")
+
+    def set(self, field, value):
+        logger.debug(self.ifname + ": SET " + field + "=" + value)
+        if not "OK" in self.request("SET " + field + " " + value):
+            raise Exception("Failed to set hostapd parameter " + field)
+
+    def set_defaults(self):
+        self.set("driver", "nl80211")
+        self.set("hw_mode", "g")
+        self.set("channel", "1")
+        self.set("ieee80211n", "1")
+
+    def set_open(self, ssid):
+        self.set_defaults()
+        self.set("ssid", ssid)
+
+    def set_wpa2_psk(self, ssid, passphrase):
+        self.set_defaults()
+        self.set("ssid", ssid)
+        self.set("wpa_passphrase", passphrase)
+        self.set("wpa", "2")
+        self.set("wpa_key_mgmt", "WPA-PSK")
+        self.set("rsn_pairwise", "CCMP")
+
+    def set_wpa_psk(self, ssid, passphrase):
+        self.set_defaults()
+        self.set("ssid", ssid)
+        self.set("wpa_passphrase", passphrase)
+        self.set("wpa", "1")
+        self.set("wpa_key_mgmt", "WPA-PSK")
+        self.set("wpa_pairwise", "TKIP")
+
+    def set_wpa_psk_mixed(self, ssid, passphrase):
+        self.set_defaults()
+        self.set("ssid", ssid)
+        self.set("wpa_passphrase", passphrase)
+        self.set("wpa", "3")
+        self.set("wpa_key_mgmt", "WPA-PSK")
+        self.set("wpa_pairwise", "TKIP")
+        self.set("rsn_pairwise", "CCMP")
+
+    def set_wep(self, ssid, key):
+        self.set_defaults()
+        self.set("ssid", ssid)
+        self.set("wep_key0", key)
+
+    def enable(self):
+        if not "OK" in self.ctrl.request("ENABLE"):
+            raise Exception("Failed to enable hostapd interface " + self.ifname)
+
+    def disable(self):
+        if not "OK" in self.ctrl.request("ENABLE"):
+            raise Exception("Failed to disable hostapd interface " + self.ifname)
+
+def add_ap(ifname, params):
+        logger.info("Starting AP " + ifname)
+        hapd_global = HostapdGlobal()
+        hapd_global.remove(ifname)
+        hapd_global.add(ifname)
+        hapd = Hostapd(ifname)
+        if not hapd.ping():
+            raise Exception("Could not ping hostapd")
+        hapd.set_defaults()
+        fields = [ "ssid", "wpa_passphrase", "nas_identifier", "wpa_key_mgmt",
+                   "wpa",
+                   "wpa_pairwise", "rsn_pairwise", "auth_server_addr" ]
+        for field in fields:
+            if field in params:
+                hapd.set(field, params[field])
+        for f,v in params.items():
+            if f in fields:
+                continue
+            if isinstance(v, list):
+                for val in v:
+                    hapd.set(f, val)
+            else:
+                hapd.set(f, v)
+        hapd.enable()
+
+def wpa2_params(ssid=None, passphrase=None):
+    params = { "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK",
+               "rsn_pairwise": "CCMP" }
+    if ssid:
+        params["ssid"] = ssid
+    if passphrase:
+        params["wpa_passphrase"] = passphrase
+    return params
+
+def wpa_params(ssid=None, passphrase=None):
+    params = { "wpa": "1",
+               "wpa_key_mgmt": "WPA-PSK",
+               "wpa_pairwise": "TKIP" }
+    if ssid:
+        params["ssid"] = ssid
+    if passphrase:
+        params["wpa_passphrase"] = passphrase
+    return params
+
+def wpa_mixed_params(ssid=None, passphrase=None):
+    params = { "wpa": "3",
+               "wpa_key_mgmt": "WPA-PSK",
+               "wpa_pairwise": "TKIP",
+               "rsn_pairwise": "CCMP" }
+    if ssid:
+        params["ssid"] = ssid
+    if passphrase:
+        params["wpa_passphrase"] = passphrase
+    return params
diff --git a/tests/hwsim/hwsim_utils.py b/tests/hwsim/hwsim_utils.py
new file mode 100644 (file)
index 0000000..b48cc41
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+#
+# hwsim testing utilities
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+def test_connectivity(ifname1, ifname2):
+    if os.path.isfile("../../mac80211_hwsim/tools/hwsim_test"):
+        hwsim_test = "../../mac80211_hwsim/tools/hwsim_test"
+    else:
+        hwsim_test = "hwsim_test"
+    cmd = ["sudo",
+           hwsim_test,
+           ifname1,
+           ifname2]
+    try:
+        s = subprocess.check_output(cmd)
+        logger.debug(s)
+    except subprocess.CalledProcessError, e:
+        print "hwsim failed: " + str(e.returncode)
+        print e.output
+        raise
+
+def test_connectivity_p2p(dev1, dev2):
+    ifname1 = dev1.group_ifname if dev1.group_ifname else dev1.ifname
+    ifname2 = dev2.group_ifname if dev2.group_ifname else dev2.ifname
+    test_connectivity(ifname1, ifname2)
+
+def test_connectivity_sta(dev1, dev2):
+    ifname1 = dev1.ifname
+    ifname2 = dev2.ifname
+    test_connectivity(ifname1, ifname2)
diff --git a/tests/hwsim/p2p0.conf b/tests/hwsim/p2p0.conf
new file mode 100644 (file)
index 0000000..9482bdc
--- /dev/null
@@ -0,0 +1,3 @@
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=Device A
+p2p_no_group_iface=1
diff --git a/tests/hwsim/p2p1.conf b/tests/hwsim/p2p1.conf
new file mode 100644 (file)
index 0000000..3622b15
--- /dev/null
@@ -0,0 +1,3 @@
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=Device B
+p2p_no_group_iface=1
diff --git a/tests/hwsim/p2p2.conf b/tests/hwsim/p2p2.conf
new file mode 100644 (file)
index 0000000..eda52e1
--- /dev/null
@@ -0,0 +1,3 @@
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=Device C
+p2p_no_group_iface=1
diff --git a/tests/hwsim/run-all.sh b/tests/hwsim/run-all.sh
new file mode 100755 (executable)
index 0000000..3ef4666
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+errors=0
+umask 0002
+./start.sh
+DATE=`ls -1tr logs | tail -1 | cut -f1 -d-`
+./run-tests.py -e logs/$DATE-failed || errors=1
+./stop-wifi.sh
+if [ $errors -gt 0 ]; then
+    tar czf /tmp/hwsim-tests-$DATE-FAILED.tar.gz logs/$DATE*
+    exit 1
+fi
diff --git a/tests/hwsim/run-tests.py b/tests/hwsim/run-tests.py
new file mode 100755 (executable)
index 0000000..364115a
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/python
+#
+# AP tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import re
+import sys
+import time
+
+import logging
+
+from wpasupplicant import WpaSupplicant
+from hostapd import HostapdGlobal
+
+def reset_devs(dev, apdev):
+    hapd = HostapdGlobal()
+    for d in dev:
+        d.reset()
+    for ap in apdev:
+        hapd.remove(ap['ifname'])
+
+def main():
+    test_file = None
+    error_file = None
+    idx = 1
+    if len(sys.argv) > 1 and sys.argv[1] == '-d':
+        logging.basicConfig(level=logging.DEBUG)
+        idx = idx + 1
+    elif len(sys.argv) > 1 and sys.argv[1] == '-q':
+        logging.basicConfig(level=logging.WARNING)
+        idx = idx + 1
+    else:
+        logging.basicConfig(level=logging.INFO)
+
+    if len(sys.argv) > idx + 1 and sys.argv[idx] == '-e':
+        error_file = sys.argv[idx + 1]
+        idx = idx + 2
+
+    if len(sys.argv) > idx + 1 and sys.argv[idx] == '-f':
+        test_file = sys.argv[idx + 1]
+        idx = idx + 2
+
+    if len(sys.argv) > idx:
+        test_filter = sys.argv[idx]
+    else:
+        test_filter = None
+
+    dev0 = WpaSupplicant('wlan0', '/tmp/wpas-wlan0')
+    dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+    dev2 = WpaSupplicant('wlan2', '/tmp/wpas-wlan2')
+    dev = [ dev0, dev1, dev2 ]
+    apdev = [ ]
+    apdev.append({"ifname": 'wlan3', "bssid": "02:00:00:00:03:00"})
+    apdev.append({"ifname": 'wlan4', "bssid": "02:00:00:00:04:00"})
+
+    for d in dev:
+        if not d.ping():
+            print d.ifname + ": No response from wpa_supplicant"
+            return
+        print "DEV: " + d.ifname + ": " + d.p2p_dev_addr()
+    for ap in apdev:
+        print "APDEV: " + ap['ifname']
+
+    tests = []
+    for t in os.listdir("."):
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            if test_file and test_file not in t:
+                continue
+            print "Import test cases from " + t
+            mod = __import__(m.group(1))
+            for s in dir(mod):
+                if s.startswith("test_"):
+                    func = mod.__dict__.get(s)
+                    tests.append(func)
+
+    passed = []
+    failed = []
+
+    for t in tests:
+        if test_filter:
+            if test_filter != t.__name__:
+                continue
+        reset_devs(dev, apdev)
+        print "START " + t.__name__
+        if t.__doc__:
+            print "Test: " + t.__doc__
+        for d in dev:
+            d.request("NOTE TEST-START " + t.__name__)
+        try:
+            if t.func_code.co_argcount > 1:
+                t(dev, apdev)
+            else:
+                t(dev)
+            passed.append(t.__name__)
+            print "PASS " + t.__name__
+        except Exception, e:
+            print e
+            failed.append(t.__name__)
+            print "FAIL " + t.__name__
+        for d in dev:
+            d.request("NOTE TEST-STOP " + t.__name__)
+
+    if not test_filter:
+        reset_devs(dev, apdev)
+
+    print
+    if len(failed):
+        print "passed " + str(len(passed)) + " test case(s)"
+        print "failed tests: " + str(failed)
+        if error_file:
+            f = open(error_file, 'w')
+            f.write(str(failed) + '\n')
+            f.close()
+        sys.exit(1)
+    print "passed all " + str(len(passed)) + " test case(s)"
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/hwsim/sta-dummy.conf b/tests/hwsim/sta-dummy.conf
new file mode 100644 (file)
index 0000000..52b7205
--- /dev/null
@@ -0,0 +1,7 @@
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+
+network={
+       disabled=0
+       ssid="test"
+       key_mgmt=NONE
+}
diff --git a/tests/hwsim/start-p2p-concurrent.sh b/tests/hwsim/start-p2p-concurrent.sh
new file mode 100755 (executable)
index 0000000..969249d
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+WPAS=$DIR/../../wpa_supplicant/wpa_supplicant
+WLANTEST=$DIR/../../wlantest/wlantest
+
+$DIR/stop-wifi.sh
+sudo modprobe mac80211_hwsim radios=3
+sudo iw wlan0 interface add sta0 type station
+sudo iw wlan1 interface add sta1 type station
+sudo iw wlan2 interface add sta2 type station
+mkdir -p $DIR/logs
+DATE=`date +%s`
+sudo ifconfig hwsim0 up
+sudo $WLANTEST -i hwsim0 -c -d > $DIR/logs/$DATE-hwsim0 &
+sudo $WPAS -Dnl80211 -iwlan0 -c $DIR/p2p0.conf -N -Dnl80211 -ista0 -c $DIR/sta-dummy.conf -ddKt > $DIR/logs/$DATE-log0 &
+sudo $WPAS -Dnl80211 -iwlan1 -c $DIR/p2p1.conf -N -Dnl80211 -ista1 -c $DIR/sta-dummy.conf -ddKt > $DIR/logs/$DATE-log1 &
+sudo $WPAS -Dnl80211 -iwlan2 -c $DIR/p2p2.conf -N -Dnl80211 -ista2 -c $DIR/sta-dummy.conf -ddKt > $DIR/logs/$DATE-log2 &
+sleep 1
diff --git a/tests/hwsim/start.sh b/tests/hwsim/start.sh
new file mode 100755 (executable)
index 0000000..be5070d
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+WPAS=$DIR/../../wpa_supplicant/wpa_supplicant
+HAPD=$DIR/../../hostapd/hostapd
+WLANTEST=$DIR/../../wlantest/wlantest
+
+$DIR/stop-wifi.sh
+sudo modprobe mac80211_hwsim radios=5
+mkdir -p $DIR/logs
+DATE=`date +%s`
+sudo ifconfig hwsim0 up
+sudo $WLANTEST -i hwsim0 -c -d > $DIR/logs/$DATE-hwsim0 &
+sudo tcpdump -ni hwsim0 -s 2500 -w $DIR/logs/$DATE-hwsim0.dump &
+sudo $WPAS -g /tmp/wpas-wlan0 -Gadmin -Dnl80211 -iwlan0 -c $DIR/p2p0.conf -ddKt > $DIR/logs/$DATE-log0 &
+sudo $WPAS -g /tmp/wpas-wlan1 -Gadmin -Dnl80211 -iwlan1 -c $DIR/p2p1.conf -ddKt > $DIR/logs/$DATE-log1 &
+sudo $WPAS -g /tmp/wpas-wlan2 -Gadmin -Dnl80211 -iwlan2 -c $DIR/p2p2.conf -ddKt > $DIR/logs/$DATE-log2 &
+sudo $HAPD -ddKt -g /var/run/hostapd-global -G admin -ddKt > $DIR/logs/$DATE-hostapd &
+sleep 1
+sudo chown $USER $DIR/logs/$DATE-hwsim0.dump
diff --git a/tests/hwsim/stop-wifi.sh b/tests/hwsim/stop-wifi.sh
new file mode 100755 (executable)
index 0000000..6464e67
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+sudo killall -q hostapd
+sudo killall -q wpa_supplicant
+sudo killall -q wlantest
+sudo killall -q tcpdump
+if grep -q hwsim0 /proc/net/dev; then
+    sudo ifconfig hwsim0 down
+fi
+if grep -q mac80211_hwsim /proc/modules ; then
+    sudo rmmod mac80211_hwsim 
+fi
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
new file mode 100644 (file)
index 0000000..c206bcf
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/python
+#
+# Fast BSS Transition tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+import hostapd
+from wlantest import Wlantest
+
+def ft_base_rsn():
+    params = { "wpa": "2",
+               "wpa_key_mgmt": "FT-PSK",
+               "rsn_pairwise": "CCMP" }
+    return params
+
+def ft_base_mixed():
+    params = { "wpa": "3",
+               "wpa_key_mgmt": "WPA-PSK FT-PSK",
+               "wpa_pairwise": "TKIP",
+               "rsn_pairwise": "CCMP" }
+    return params
+
+def ft_params(rsn=True, ssid=None, passphrase=None):
+    if rsn:
+        params = ft_base_rsn()
+    else:
+        params = ft_base_mixed()
+    if ssid:
+        params["ssid"] = ssid
+    if passphrase:
+        params["wpa_passphrase"] = passphrase
+
+    params["mobility_domain"] = "a1b2"
+    params["r0_key_lifetime"] = "10000"
+    params["pmk_r1_push"] = "1"
+    params["reassociation_deadline"] = "1000"
+    return params
+
+def ft_params1(rsn=True, ssid=None, passphrase=None):
+    params = ft_params(rsn, ssid, passphrase)
+    params['nas_identifier'] = "nas1.w1.fi"
+    params['r1_key_holder'] = "000102030405"
+    params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f",
+                       "02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f" ]
+    params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f"
+    return params
+
+def ft_params2(rsn=True, ssid=None, passphrase=None):
+    params = ft_params(rsn, ssid, passphrase)
+    params['nas_identifier'] = "nas2.w1.fi"
+    params['r1_key_holder'] = "000102030406"
+    params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f",
+                       "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f" ]
+    params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f"
+    return params
+
+def run_roams(dev, apdev, ssid, passphrase):
+    logger.info("Connect to first AP")
+    dev.connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
+                ieee80211w="1")
+    if dev.get_status_field('bssid') == apdev[0]['bssid']:
+        ap1 = apdev[0]
+        ap2 = apdev[1]
+    else:
+        ap1 = apdev[1]
+        ap2 = apdev[0]
+    hwsim_utils.test_connectivity(dev.ifname, ap1['ifname'])
+
+    logger.info("Roam to the second AP")
+    dev.roam(ap2['bssid'])
+    if dev.get_status_field('bssid') != ap2['bssid']:
+        raise Exception("Did not connect to correct AP")
+    hwsim_utils.test_connectivity(dev.ifname, ap2['ifname'])
+
+    logger.info("Roam back to the first AP")
+    dev.roam(ap1['bssid'])
+    if dev.get_status_field('bssid') != ap1['bssid']:
+        raise Exception("Did not connect to correct AP")
+    hwsim_utils.test_connectivity(dev.ifname, ap1['ifname'])
+
+def test_ap_ft(dev, apdev):
+    """WPA2-PSK-FT AP"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    params = ft_params2(ssid=ssid, passphrase=passphrase)
+    hostapd.add_ap(apdev[1]['ifname'], params)
+
+    run_roams(dev[0], apdev, ssid, passphrase)
+
+def test_ap_ft_mixed(dev, apdev):
+    """WPA2-PSK-FT mixed-mode AP"""
+    ssid = "test-ft-mixed"
+    passphrase="12345678"
+
+    params = ft_params1(rsn=False, ssid=ssid, passphrase=passphrase)
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    params = ft_params2(rsn=False, ssid=ssid, passphrase=passphrase)
+    hostapd.add_ap(apdev[1]['ifname'], params)
+
+    run_roams(dev[0], apdev, ssid, passphrase)
+
+def test_ap_ft_pmf(dev, apdev):
+    """WPA2-PSK-FT AP with PMF"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    params["ieee80211w"] = "2";
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    params = ft_params2(ssid=ssid, passphrase=passphrase)
+    params["ieee80211w"] = "2";
+    hostapd.add_ap(apdev[1]['ifname'], params)
+
+    run_roams(dev[0], apdev, ssid, passphrase)
diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py
new file mode 100644 (file)
index 0000000..def7bfe
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+#
+# Hotspot 2.0 tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hostapd
+
+def hs20_ap_params():
+    params = hostapd.wpa2_params(ssid="test-hs20")
+    params['wpa_key_mgmt'] = "WPA-EAP"
+    params['ieee80211w'] = "1"
+    params['ieee8021x'] = "1"
+    params['auth_server_addr'] = "127.0.0.1"
+    params['auth_server_port'] = "1812"
+    params['auth_server_shared_secret'] = "radius"
+    params['interworking'] = "1"
+    params['access_network_type'] = "14"
+    params['internet'] = "1"
+    params['asra'] = "0"
+    params['esr'] = "0"
+    params['uesa'] = "0"
+    params['venue_group'] = "7"
+    params['venue_type'] = "1"
+    params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
+    params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
+                                     "fedcba" ]
+    params['domain_name'] = "example.com,another.example.com"
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
+                            "0,another.example.com" ]
+    params['hs20'] = "1"
+    params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
+    params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
+    params['hs20_operating_class'] = "5173"
+    params['anqp_3gpp_cell_net'] = "244,91"
+    return params
+
+def test_ap_hs20_select(dev, apdev):
+    """Hotspot 2.0 network selection"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].request("SET interworking 1")
+    dev[0].request("SET hs20 1")
+
+    id = dev[0].add_cred()
+    dev[0].set_cred_quoted(id, "realm", "example.com");
+    dev[0].set_cred_quoted(id, "username", "test");
+    dev[0].set_cred_quoted(id, "password", "secret");
+    dev[0].set_cred_quoted(id, "domain", "example.com");
+
+    dev[0].dump_monitor()
+    dev[0].request("INTERWORKING_SELECT")
+    ev = dev[0].wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
+                           timeout=15)
+    if ev is None:
+        raise Exception("Network selection timed out");
+    if "INTERWORKING-NO-MATCH" in ev:
+        raise Exception("Matching network not found")
+    if bssid not in ev:
+        raise Exception("Unexpected BSSID in match")
+    if "type=home" not in ev:
+        raise Exception("Home network not recognized")
+
+    dev[0].set_cred_quoted(id, "domain", "no.match.example.com");
+    dev[0].dump_monitor()
+    dev[0].request("INTERWORKING_SELECT")
+    ev = dev[0].wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
+                           timeout=15)
+    if ev is None:
+        raise Exception("Network selection timed out");
+    if "INTERWORKING-NO-MATCH" in ev:
+        raise Exception("Matching network not found")
+    if bssid not in ev:
+        raise Exception("Unexpected BSSID in match")
+    if "type=roaming" not in ev:
+        raise Exception("Roaming network not recognized")
+
+    dev[0].set_cred_quoted(id, "realm", "no.match.example.com");
+    dev[0].dump_monitor()
+    dev[0].request("INTERWORKING_SELECT")
+    ev = dev[0].wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
+                           timeout=15)
+    if ev is None:
+        raise Exception("Network selection timed out");
+    if "INTERWORKING-NO-MATCH" not in ev:
+        raise Exception("Unexpected network match")
diff --git a/tests/hwsim/test_ap_pmf.py b/tests/hwsim/test_ap_pmf.py
new file mode 100644 (file)
index 0000000..33e023b
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+#
+# Protected management frames tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+import hostapd
+from wlantest import Wlantest
+
+def test_ap_pmf_required(dev, apdev):
+    """WPA2-PSK AP with PMF required"""
+    ssid = "test-pmf-required"
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
+    params["ieee80211w"] = "2";
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    dev[1].connect(ssid, psk="12345678", ieee80211w="2",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[1].ifname, apdev[0]['ifname'])
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd.request("SA_QUERY " + dev[0].p2p_interface_addr())
+    hapd.request("SA_QUERY " + dev[1].p2p_interface_addr())
+    wt.require_ap_pmf_mandatory(apdev[0]['bssid'])
+    wt.require_sta_pmf(apdev[0]['bssid'], dev[0].p2p_interface_addr())
+    wt.require_sta_pmf_mandatory(apdev[0]['bssid'], dev[1].p2p_interface_addr())
+    time.sleep(0.1)
+    if wt.get_sta_counter("valid_saqueryresp_tx", apdev[0]['bssid'],
+                          dev[0].p2p_interface_addr()) < 1:
+        raise Exception("STA did not reply to SA Query")
+    if wt.get_sta_counter("valid_saqueryresp_tx", apdev[0]['bssid'],
+                          dev[1].p2p_interface_addr()) < 1:
+        raise Exception("STA did not reply to SA Query")
+
+def test_ap_pmf_optional(dev, apdev):
+    """WPA2-PSK AP with PMF optional"""
+    ssid = "test-pmf-optional"
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK";
+    params["ieee80211w"] = "1";
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    dev[1].connect(ssid, psk="12345678", ieee80211w="2",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[1].ifname, apdev[0]['ifname'])
+    wt.require_ap_pmf_optional(apdev[0]['bssid'])
+    wt.require_sta_pmf(apdev[0]['bssid'], dev[0].p2p_interface_addr())
+    wt.require_sta_pmf_mandatory(apdev[0]['bssid'], dev[1].p2p_interface_addr())
+
+def test_ap_pmf_optional_2akm(dev, apdev):
+    """WPA2-PSK AP with PMF optional (2 AKMs)"""
+    ssid = "test-pmf-optional-2akm"
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK WPA-PSK-SHA256";
+    params["ieee80211w"] = "1";
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    dev[1].connect(ssid, psk="12345678", ieee80211w="2",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[1].ifname, apdev[0]['ifname'])
+    wt.require_ap_pmf_optional(apdev[0]['bssid'])
+    wt.require_sta_pmf(apdev[0]['bssid'], dev[0].p2p_interface_addr())
+    wt.require_sta_key_mgmt(apdev[0]['bssid'], dev[0].p2p_interface_addr(),
+                            "PSK-SHA256")
+    wt.require_sta_pmf_mandatory(apdev[0]['bssid'], dev[1].p2p_interface_addr())
+    wt.require_sta_key_mgmt(apdev[0]['bssid'], dev[1].p2p_interface_addr(),
+                            "PSK-SHA256")
+
+def test_ap_pmf_negative(dev, apdev):
+    """WPA2-PSK AP without PMF (negative test)"""
+    ssid = "test-pmf-negative"
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    try:
+        dev[1].connect(ssid, psk="12345678", ieee80211w="2",
+                       key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2")
+        hwsim_utils.test_connectivity(dev[1].ifname, apdev[0]['ifname'])
+        raise Exception("PMF required STA connected to no PMF AP")
+    except Exception, e:
+        logger.debug("Ignore expected exception: " + str(e))
+    wt.require_ap_no_pmf(apdev[0]['bssid'])
diff --git a/tests/hwsim/test_ap_roam.py b/tests/hwsim/test_ap_roam.py
new file mode 100644 (file)
index 0000000..3a966f7
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+#
+# Roaming tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+import hostapd
+
+def test_ap_roam_open(dev, apdev):
+    """Roam between two open APs"""
+    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    dev[0].connect("test-open", key_mgmt="NONE")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test-open" })
+    dev[0].scan(type="ONLY")
+    dev[0].roam(apdev[1]['bssid'])
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[1]['ifname'])
+    dev[0].roam(apdev[0]['bssid'])
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+
+def test_ap_roam_wpa2_psk(dev, apdev):
+    """Roam between two WPA2-PSK APs"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-psk", psk="12345678")
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
+    hostapd.add_ap(apdev[1]['ifname'], params)
+    dev[0].scan(type="ONLY")
+    dev[0].roam(apdev[1]['bssid'])
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[1]['ifname'])
+    dev[0].roam(apdev[0]['bssid'])
+    hwsim_utils.test_connectivity(dev[0].ifname, apdev[0]['ifname'])
diff --git a/tests/hwsim/test_ap_tdls.py b/tests/hwsim/test_ap_tdls.py
new file mode 100644 (file)
index 0000000..9abada8
--- /dev/null
@@ -0,0 +1,258 @@
+#!/usr/bin/python
+#
+# TDLS tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+from hostapd import HostapdGlobal
+from hostapd import Hostapd
+import hostapd
+from wlantest import Wlantest
+
+def start_ap_wpa2_psk(ifname):
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hostapd.add_ap(ifname, params)
+
+def connectivity(dev, ap_ifname):
+    hwsim_utils.test_connectivity_sta(dev[0], dev[1])
+    hwsim_utils.test_connectivity(dev[0].ifname, ap_ifname)
+    hwsim_utils.test_connectivity(dev[1].ifname, ap_ifname)
+
+def connect_2sta(dev, ssid, ap_ifname):
+    dev[0].connect(ssid, psk="12345678")
+    dev[1].connect(ssid, psk="12345678")
+    connectivity(dev, ap_ifname)
+
+def connect_2sta_wpa2_psk(dev, ap_ifname):
+    connect_2sta(dev, "test-wpa2-psk", ap_ifname)
+
+def connect_2sta_wpa_psk(dev, ap_ifname):
+    connect_2sta(dev, "test-wpa-psk", ap_ifname)
+
+def connect_2sta_wpa_psk_mixed(dev, ap_ifname):
+    dev[0].connect("test-wpa-mixed-psk", psk="12345678", proto="WPA")
+    dev[1].connect("test-wpa-mixed-psk", psk="12345678", proto="WPA2")
+    connectivity(dev, ap_ifname)
+
+def connect_2sta_wep(dev, ap_ifname):
+    dev[0].connect("test-wep", key_mgmt="NONE", wep_key0='"hello"')
+    dev[1].connect("test-wep", key_mgmt="NONE", wep_key0='"hello"')
+    connectivity(dev, ap_ifname)
+
+def connect_2sta_open(dev, ap_ifname):
+    dev[0].connect("test-open", key_mgmt="NONE")
+    dev[1].connect("test-open", key_mgmt="NONE")
+    connectivity(dev, ap_ifname)
+
+def wlantest_setup():
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    wt.add_wepkey("68656c6c6f")
+
+def wlantest_tdls_packet_counters(bssid, addr0, addr1):
+    wt = Wlantest()
+    dl = wt.get_tdls_counter("valid_direct_link", bssid, addr0, addr1)
+    inv_dl = wt.get_tdls_counter("invalid_direct_link", bssid, addr0, addr1)
+    ap = wt.get_tdls_counter("valid_ap_path", bssid, addr0, addr1)
+    inv_ap = wt.get_tdls_counter("invalid_ap_path", bssid, addr0, addr1)
+    return [dl,inv_dl,ap,inv_ap]
+
+def tdls_check_dl(sta0, sta1, bssid, addr0, addr1):
+    wt = Wlantest()
+    wt.tdls_clear(bssid, addr0, addr1)
+    hwsim_utils.test_connectivity_sta(sta0, sta1)
+    [dl,inv_dl,ap,inv_ap] = wlantest_tdls_packet_counters(bssid, addr0, addr1)
+    if dl == 0:
+        raise Exception("No valid frames through direct link")
+    if inv_dl > 0:
+        raise Exception("Invalid frames through direct link")
+    if ap > 0:
+        raise Exception("Unexpected frames through AP path")
+    if inv_ap > 0:
+        raise Exception("Invalid frames through AP path")
+
+def tdls_check_ap(sta0, sta1, bssid, addr0, addr1):
+    wt = Wlantest()
+    wt.tdls_clear(bssid, addr0, addr1);
+    hwsim_utils.test_connectivity_sta(sta0, sta1)
+    [dl,inv_dl,ap,inv_ap] = wlantest_tdls_packet_counters(bssid, addr0, addr1)
+    if dl > 0:
+        raise Exception("Unexpected frames through direct link")
+    if inv_dl > 0:
+        raise Exception("Invalid frames through direct link")
+    if ap == 0:
+        raise Exception("No valid frames through AP path")
+    if inv_ap > 0:
+        raise Exception("Invalid frames through AP path")
+
+def setup_tdls(sta0, sta1, bssid, reverse=False, expect_fail=False):
+    logger.info("Setup TDLS")
+    addr0 = sta0.p2p_interface_addr()
+    addr1 = sta1.p2p_interface_addr()
+    wt = Wlantest()
+    wt.tdls_clear(bssid, addr0, addr1);
+    wt.tdls_clear(bssid, addr1, addr0);
+    sta0.tdls_setup(addr1)
+    time.sleep(1)
+    if expect_fail:
+        tdls_check_ap(sta0, sta1, bssid, addr0, addr1)
+        return
+    if reverse:
+        addr1 = sta0.p2p_interface_addr()
+        addr0 = sta1.p2p_interface_addr()
+    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr0, addr1);
+    if conf == 0:
+        raise Exception("No TDLS Setup Confirm (success) seen")
+    tdls_check_dl(sta0, sta1, bssid, addr0, addr1)
+
+def teardown_tdls(sta0, sta1, bssid):
+    logger.info("Teardown TDLS")
+    addr0 = sta0.p2p_interface_addr()
+    addr1 = sta1.p2p_interface_addr()
+    sta0.tdls_teardown(addr1)
+    time.sleep(1)
+    wt = Wlantest()
+    teardown = wt.get_tdls_counter("teardown", bssid, addr0, addr1);
+    if teardown == 0:
+        raise Exception("No TDLS Setup Teardown seen")
+    tdls_check_ap(sta0, sta1, bssid, addr0, addr1)
+
+def test_ap_wpa2_tdls(dev, apdev):
+    """WPA2-PSK AP and two stations using TDLS"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    setup_tdls(dev[0], dev[1], bssid)
+    teardown_tdls(dev[0], dev[1], bssid)
+    setup_tdls(dev[1], dev[0], bssid)
+    #teardown_tdls(dev[0], dev[1], bssid)
+
+def test_ap_wpa2_tdls_concurrent_init(dev, apdev):
+    """Concurrent TDLS setup initiation"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[0].request("SET tdls_testing 0x80")
+    setup_tdls(dev[1], dev[0], bssid, reverse=True)
+
+def test_ap_wpa2_tdls_concurrent_init2(dev, apdev):
+    """Concurrent TDLS setup initiation (reverse)"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[1].request("SET tdls_testing 0x80")
+    setup_tdls(dev[0], dev[1], bssid)
+
+def test_ap_wpa2_tdls_decline_resp(dev, apdev):
+    """Decline TDLS Setup Response"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[1].request("SET tdls_testing 0x200")
+    setup_tdls(dev[1], dev[0], bssid, expect_fail=True)
+
+def test_ap_wpa2_tdls_long_lifetime(dev, apdev):
+    """TDLS with long TPK lifetime"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[1].request("SET tdls_testing 0x40")
+    setup_tdls(dev[1], dev[0], bssid)
+
+def test_ap_wpa2_tdls_long_frame(dev, apdev):
+    """TDLS with long setup/teardown frames"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[0].request("SET tdls_testing 0x1")
+    dev[1].request("SET tdls_testing 0x1")
+    setup_tdls(dev[1], dev[0], bssid)
+    teardown_tdls(dev[1], dev[0], bssid)
+    setup_tdls(dev[0], dev[1], bssid)
+
+def test_ap_wpa2_tdls_reneg(dev, apdev):
+    """Renegotiate TDLS link"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    setup_tdls(dev[1], dev[0], bssid)
+    setup_tdls(dev[0], dev[1], bssid)
+
+def test_ap_wpa2_tdls_wrong_lifetime_resp(dev, apdev):
+    """Incorrect TPK lifetime in TDLS Setup Response"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[1].request("SET tdls_testing 0x10")
+    setup_tdls(dev[0], dev[1], bssid, expect_fail=True)
+
+def test_ap_wpa2_tdls_diff_rsnie(dev, apdev):
+    """TDLS with different RSN IEs"""
+    start_ap_wpa2_psk(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa2_psk(dev, apdev[0]['ifname'])
+    dev[1].request("SET tdls_testing 0x2")
+    setup_tdls(dev[1], dev[0], bssid)
+    teardown_tdls(dev[1], dev[0], bssid)
+
+def test_ap_wpa_tdls(dev, apdev):
+    """WPA-PSK AP and two stations using TDLS"""
+    hostapd.add_ap(apdev[0]['ifname'],
+                   hostapd.wpa_params(ssid="test-wpa-psk",
+                                      passphrase="12345678"))
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa_psk(dev, apdev[0]['ifname'])
+    setup_tdls(dev[0], dev[1], bssid)
+    teardown_tdls(dev[0], dev[1], bssid)
+    setup_tdls(dev[1], dev[0], bssid)
+
+def test_ap_wpa_mixed_tdls(dev, apdev):
+    """WPA+WPA2-PSK AP and two stations using TDLS"""
+    hostapd.add_ap(apdev[0]['ifname'],
+                   hostapd.wpa_mixed_params(ssid="test-wpa-mixed-psk",
+                                            passphrase="12345678"))
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wpa_psk_mixed(dev, apdev[0]['ifname'])
+    setup_tdls(dev[0], dev[1], bssid)
+    teardown_tdls(dev[0], dev[1], bssid)
+    setup_tdls(dev[1], dev[0], bssid)
+
+def test_ap_wep_tdls(dev, apdev):
+    """WEP AP and two stations using TDLS"""
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": "test-wep", "wep_key0": '"hello"' })
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_wep(dev, apdev[0]['ifname'])
+    setup_tdls(dev[0], dev[1], bssid)
+    teardown_tdls(dev[0], dev[1], bssid)
+    setup_tdls(dev[1], dev[0], bssid)
+
+def test_ap_open_tdls(dev, apdev):
+    """Open AP and two stations using TDLS"""
+    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    bssid = apdev[0]['bssid']
+    wlantest_setup()
+    connect_2sta_open(dev, apdev[0]['ifname'])
+    setup_tdls(dev[0], dev[1], bssid)
+    teardown_tdls(dev[0], dev[1], bssid)
+    setup_tdls(dev[1], dev[0], bssid)
diff --git a/tests/hwsim/test_ap_wps.py b/tests/hwsim/test_ap_wps.py
new file mode 100644 (file)
index 0000000..84f206f
--- /dev/null
@@ -0,0 +1,317 @@
+#!/usr/bin/python
+#
+# WPS tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+import hostapd
+
+def test_ap_wps_init(dev, apdev):
+    """Initial AP configuration with first WPS Enrollee"""
+    ssid = "test-wps"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step")
+    hapd.request("WPS_PBC")
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PBC")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+def test_ap_wps_conf(dev, apdev):
+    """WPS PBC provisioning with configured AP"""
+    ssid = "test-wps-conf"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step")
+    hapd.request("WPS_PBC")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PBC")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED':
+        raise Exception("Not fully connected")
+    if status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Unexpected BSSID")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+def test_ap_wps_conf_pin(dev, apdev):
+    """WPS PIN provisioning with configured AP"""
+    ssid = "test-wps-conf-pin"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step")
+    pin = dev[0].wps_read_pin()
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PIN any " + pin)
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+def test_ap_wps_reg_connect(dev, apdev):
+    """WPS registrar using AP PIN to connect"""
+    ssid = "test-wps-reg-ap-pin"
+    appin = "12345670"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                     "ap_pin": appin})
+    logger.info("WPS provisioning step")
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].dump_monitor()
+    dev[0].wps_reg(apdev[0]['bssid'], appin)
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+def test_ap_wps_reg_config(dev, apdev):
+    """WPS registrar configuring and AP using AP PIN"""
+    ssid = "test-wps-init-ap-pin"
+    appin = "12345670"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "ap_pin": appin})
+    logger.info("WPS configuration step")
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].dump_monitor()
+    new_ssid = "wps-new-ssid"
+    new_passphrase = "1234567890"
+    dev[0].wps_reg(apdev[0]['bssid'], appin, new_ssid, "WPA2PSK", "CCMP",
+                   new_passphrase)
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != new_ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+def test_ap_wps_pbc_overlap_2ap(dev, apdev):
+    """WPS PBC session overlap with two active APs"""
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": "wps1", "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                     "wps_independent": "1"})
+    hostapd.add_ap(apdev[1]['ifname'],
+                   { "ssid": "wps2", "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "123456789", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                     "wps_independent": "1"})
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd.request("WPS_PBC")
+    hapd2 = hostapd.Hostapd(apdev[1]['ifname'])
+    hapd2.request("WPS_PBC")
+    logger.info("WPS provisioning step")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PBC")
+    ev = dev[0].wait_event(["WPS-OVERLAP-DETECTED"], timeout=15)
+    if ev is None:
+        raise Exception("PBC session overlap not detected")
+
+def test_ap_wps_pbc_overlap_2sta(dev, apdev):
+    """WPS PBC session overlap with two active STAs"""
+    ssid = "test-wps-pbc-overlap"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step")
+    hapd.request("WPS_PBC")
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[1].request("SET ignore_old_scan_res 1")
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+    dev[0].request("WPS_PBC")
+    dev[1].request("WPS_PBC")
+    ev = dev[0].wait_event(["WPS-M2D"], timeout=15)
+    if ev is None:
+        raise Exception("PBC session overlap not detected (dev0)")
+    if "config_error=12" not in ev:
+        raise Exception("PBC session overlap not correctly reported (dev0)")
+    ev = dev[1].wait_event(["WPS-M2D"], timeout=15)
+    if ev is None:
+        raise Exception("PBC session overlap not detected (dev1)")
+    if "config_error=12" not in ev:
+        raise Exception("PBC session overlap not correctly reported (dev1)")
+
+def test_ap_wps_er_add_enrollee(dev, apdev):
+    """WPS ER configuring AP and adding a new enrollee using PIN"""
+    ssid = "wps-er-add-enrollee"
+    ap_pin = "12345670"
+    ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1",
+                     "device_name": "Wireless AP", "manufacturer": "Company",
+                     "model_name": "WAP", "model_number": "123",
+                     "serial_number": "12345", "device_type": "6-0050F204-1",
+                     "os_version": "01020300",
+                     "config_methods": "label push_button",
+                     "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo"})
+    logger.info("WPS configuration step")
+    new_passphrase = "1234567890"
+    dev[0].dump_monitor()
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].wps_reg(apdev[0]['bssid'], ap_pin, ssid, "WPA2PSK", "CCMP",
+                   new_passphrase)
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
+    logger.info("Start ER")
+    dev[0].request("WPS_ER_START ifname=lo")
+    ev = dev[0].wait_event(["WPS-ER-AP-ADD"], timeout=15)
+    if ev is None:
+        raise Exception("AP discovery timed out")
+    if ap_uuid not in ev:
+        raise Exception("Expected AP UUID not found")
+
+    logger.info("Learn AP configuration through UPnP")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_ER_LEARN " + ap_uuid + " " + ap_pin)
+    ev = dev[0].wait_event(["WPS-ER-AP-SETTINGS"], timeout=15)
+    if ev is None:
+        raise Exception("AP learn timed out")
+    if ap_uuid not in ev:
+        raise Exception("Expected AP UUID not in settings")
+    if "ssid=" + ssid not in ev:
+        raise Exception("Expected SSID not in settings")
+    if "key=" + new_passphrase not in ev:
+        raise Exception("Expected passphrase not in settings")
+
+    logger.info("Add Enrollee using ER")
+    pin = dev[1].wps_read_pin()
+    dev[0].dump_monitor()
+    dev[0].request("WPS_ER_PIN any " + pin + " " + dev[1].p2p_interface_addr())
+    dev[1].request("SET ignore_old_scan_res 1")
+    dev[1].dump_monitor()
+    dev[1].request("WPS_PIN any " + pin)
+    ev = dev[1].wait_event(["WPS-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("Enrollee did not report success")
+    ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    ev = dev[0].wait_event(["WPS-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("WPS ER did not report success")
+    hwsim_utils.test_connectivity_sta(dev[0], dev[1])
+
+def test_ap_wps_er_add_enrollee_pbc(dev, apdev):
+    """WPS ER connected to AP and adding a new enrollee using PBC"""
+    ssid = "wps-er-add-enrollee-pbc"
+    ap_pin = "12345670"
+    ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "2",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                     "device_name": "Wireless AP", "manufacturer": "Company",
+                     "model_name": "WAP", "model_number": "123",
+                     "serial_number": "12345", "device_type": "6-0050F204-1",
+                     "os_version": "01020300",
+                     "config_methods": "label push_button",
+                     "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo"})
+    logger.info("Learn AP configuration")
+    dev[0].dump_monitor()
+    dev[0].request("SET ignore_old_scan_res 1")
+    dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+
+    logger.info("Start ER")
+    dev[0].request("WPS_ER_START ifname=lo")
+    ev = dev[0].wait_event(["WPS-ER-AP-ADD"], timeout=15)
+    if ev is None:
+        raise Exception("AP discovery timed out")
+    if ap_uuid not in ev:
+        raise Exception("Expected AP UUID not found")
+
+    logger.info("Use learned network configuration on ER")
+    dev[0].request("WPS_ER_SET_CONFIG " + ap_uuid + " 0")
+
+    logger.info("Add Enrollee using ER and PBC")
+    dev[0].dump_monitor()
+    enrollee = dev[1].p2p_interface_addr()
+    dev[1].request("SET ignore_old_scan_res 1")
+    dev[1].dump_monitor()
+    dev[1].request("WPS_PBC")
+
+    ev = dev[0].wait_event(["WPS-ER-ENROLLEE-ADD"], timeout=15)
+    if ev is None:
+        raise Exception("Enrollee discovery timed out")
+    if enrollee not in ev:
+        raise Exception("Expected Enrollee not found")
+    dev[0].request("WPS_ER_PBC " + enrollee)
+
+    ev = dev[1].wait_event(["WPS-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("Enrollee did not report success")
+    ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    ev = dev[0].wait_event(["WPS-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("WPS ER did not report success")
+    hwsim_utils.test_connectivity_sta(dev[0], dev[1])
diff --git a/tests/hwsim/test_nfc_wps.py b/tests/hwsim/test_nfc_wps.py
new file mode 100644 (file)
index 0000000..9d5b2a4
--- /dev/null
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+#
+# WPS+NFC tests
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+import hostapd
+
+def check_wpa2_connection(sta, ap, ssid, mixed=False):
+    status = sta.get_status()
+    if status['wpa_state'] != 'COMPLETED':
+        raise Exception("Not fully connected")
+    if status['bssid'] != ap['bssid']:
+        raise Exception("Unexpected BSSID")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP':
+        raise Exception("Unexpected encryption configuration")
+    if status['group_cipher'] != 'CCMP' and not mixed:
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+    hwsim_utils.test_connectivity(sta.ifname, ap['ifname'])
+
+def ap_wps_params(ssid):
+    return { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+             "wpa_passphrase": "12345678", "wpa": "2",
+             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"}
+
+def test_nfc_wps_password_token_sta(dev, apdev):
+    """NFC tag with password token on the station/Enrollee"""
+    dev[0].request("SET ignore_old_scan_res 1")
+    ssid = "test-wps-nfc-pw-token-conf"
+    params = ap_wps_params(ssid)
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step using password token from station")
+    pw = dev[0].request("WPS_NFC_TOKEN NDEF").rstrip()
+    if "FAIL" in pw:
+        raise Exception("Failed to generate password token")
+    res = hapd.request("WPS_NFC_TAG_READ " + pw)
+    if "FAIL" in res:
+        raise Exception("Failed to provide NFC tag contents to hostapd")
+    dev[0].dump_monitor()
+    res = dev[0].request("WPS_NFC")
+    if "FAIL" in res:
+        raise Exception("Failed to start Enrollee using NFC password token")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], ssid)
+
+def test_nfc_wps_config_token(dev, apdev):
+    """NFC tag with configuration token from AP"""
+    ssid = "test-wps-nfc-conf-token"
+    params = ap_wps_params(ssid)
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("NFC configuration token from AP to station")
+    conf = hapd.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
+    if "FAIL" in conf:
+        raise Exception("Failed to generate configuration token")
+    dev[0].dump_monitor()
+    res = dev[0].request("WPS_NFC_TAG_READ " + conf)
+    if "FAIL" in res:
+        raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], ssid)
+
+def test_nfc_wps_config_token_init(dev, apdev):
+    """NFC tag with configuration token from AP with auto configuration"""
+    dev[0].request("SET ignore_old_scan_res 1")
+    ssid = "test-wps-nfc-conf-token-init"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("NFC configuration token from AP to station")
+    conf = hapd.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
+    if "FAIL" in conf:
+        raise Exception("Failed to generate configuration token")
+    dev[0].dump_monitor()
+    res = dev[0].request("WPS_NFC_TAG_READ " + conf)
+    if "FAIL" in res:
+        raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], ssid, mixed=True)
+
+def test_nfc_wps_password_token_sta_init(dev, apdev):
+    """Initial AP configuration with first WPS NFC Enrollee"""
+    dev[0].request("SET ignore_old_scan_res 1")
+    ssid = "test-wps-nfc-pw-token-init"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS provisioning step using password token from station")
+    pw = dev[0].request("WPS_NFC_TOKEN NDEF").rstrip()
+    if "FAIL" in pw:
+        raise Exception("Failed to generate password token")
+    res = hapd.request("WPS_NFC_TAG_READ " + pw)
+    if "FAIL" in res:
+        raise Exception("Failed to provide NFC tag contents to hostapd")
+    dev[0].dump_monitor()
+    res = dev[0].request("WPS_NFC")
+    if "FAIL" in res:
+        raise Exception("Failed to start Enrollee using NFC password token")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], ssid, mixed=True)
+
+def test_nfc_wps_password_token_ap(dev, apdev):
+    """WPS registrar configuring an AP using AP password token"""
+    dev[0].request("SET ignore_old_scan_res 1")
+    ssid = "test-wps-nfc-pw-token-init"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("WPS configuration step")
+    pw = hapd.request("WPS_NFC_TOKEN NDEF").rstrip()
+    if "FAIL" in pw:
+        raise Exception("Failed to generate password token")
+    res = hapd.request("WPS_NFC_TOKEN enable")
+    if "FAIL" in pw:
+        raise Exception("Failed to enable AP password token")
+    res = dev[0].request("WPS_NFC_TAG_READ " + pw)
+    if "FAIL" in res:
+        raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
+    dev[0].dump_monitor()
+    new_ssid = "test-wps-nfc-pw-token-new-ssid"
+    new_passphrase = "1234567890"
+    res = dev[0].request("WPS_REG " + apdev[0]['bssid'] + " nfc-pw " + new_ssid.encode("hex") + " WPA2PSK CCMP " + new_passphrase.encode("hex"))
+    if "FAIL" in res:
+        raise Exception("Failed to start Registrar using NFC password token")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], new_ssid, mixed=True)
+
+def test_nfc_wps_handover(dev, apdev):
+    """Connect to WPS AP with NFC connection handover"""
+    ssid = "test-wps-nfc-handover"
+    params = ap_wps_params(ssid)
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    logger.info("NFC connection handover")
+    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
+    if "FAIL" in req:
+        raise Exception("Failed to generate NFC connection handover request")
+    sel = hapd.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
+    if "FAIL" in sel:
+        raise Exception("Failed to generate NFC connection handover select")
+    res = hapd.request("NFC_REPORT_HANDOVER RESP WPS " + req + " " + sel)
+    if "FAIL" in res:
+        raise Exception("Failed to report NFC connection handover to to hostapd")
+    dev[0].dump_monitor()
+    res = dev[0].request("NFC_REPORT_HANDOVER INIT WPS " + req + " " + sel)
+    if "FAIL" in res:
+        raise Exception("Failed to report NFC connection handover to to wpa_supplicant")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Association with the AP timed out")
+    check_wpa2_connection(dev[0], apdev[0], ssid)
diff --git a/tests/hwsim/test_p2p_autogo.py b/tests/hwsim/test_p2p_autogo.py
new file mode 100644 (file)
index 0000000..e787570
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/python
+#
+# P2P autonomous GO test cases
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+from wlantest import Wlantest
+
+def autogo(go):
+    logger.info("Start autonomous GO " + go.ifname)
+    res = go.p2p_start_go()
+    logger.debug("res: " + str(res))
+
+def connect_cli(go, client):
+    logger.info("Try to connect the client to the GO")
+    pin = client.wps_read_pin()
+    go.p2p_go_authorize_client(pin)
+    client.p2p_connect_group(go.p2p_dev_addr(), pin, timeout=60)
+    logger.info("Client connected")
+    hwsim_utils.test_connectivity_p2p(go, client)
+
+def test_autogo(dev):
+    """P2P autonomous GO and client joining group"""
+    autogo(dev[0])
+    connect_cli(dev[0], dev[1])
+    dev[0].remove_group()
+    try:
+        dev[1].remove_group()
+    except:
+        pass
+
+def test_autogo_2cli(dev):
+    """P2P autonomous GO and two clients joining group"""
+    autogo(dev[0])
+    connect_cli(dev[0], dev[1])
+    connect_cli(dev[0], dev[2])
+    hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
+    dev[2].remove_group()
+    dev[1].remove_group()
+    dev[0].remove_group()
+
+def test_autogo_tdls(dev):
+    """P2P autonomous GO and two clients using TDLS"""
+    wt = Wlantest()
+    go = dev[0]
+    logger.info("Start autonomous GO with fixed parameters " + go.ifname)
+    id = go.add_network()
+    go.set_network_quoted(id, "ssid", "DIRECT-tdls")
+    go.set_network_quoted(id, "psk", "12345678")
+    go.set_network(id, "mode", "3")
+    go.set_network(id, "disabled", "2")
+    res = go.p2p_start_go(persistent=id)
+    logger.debug("res: " + str(res))
+    wt.flush()
+    wt.add_passphrase("12345678")
+    connect_cli(go, dev[1])
+    connect_cli(go, dev[2])
+    hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
+    bssid = dev[0].p2p_interface_addr()
+    addr1 = dev[1].p2p_interface_addr()
+    addr2 = dev[2].p2p_interface_addr()
+    dev[1].tdls_setup(addr2)
+    time.sleep(1)
+    hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
+    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr1, addr2);
+    if conf == 0:
+        raise Exception("No TDLS Setup Confirm (success) seen")
+    dl = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2);
+    if dl == 0:
+        raise Exception("No valid frames through direct link")
+    wt.tdls_clear(bssid, addr1, addr2);
+    dev[1].tdls_teardown(addr2)
+    time.sleep(1)
+    teardown = wt.get_tdls_counter("teardown", bssid, addr1, addr2);
+    if teardown == 0:
+        raise Exception("No TDLS Setup Teardown seen")
+    wt.tdls_clear(bssid, addr1, addr2);
+    hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
+    ap_path = wt.get_tdls_counter("valid_ap_path", bssid, addr1, addr2);
+    if ap_path == 0:
+        raise Exception("No valid frames via AP path")
+    direct_link = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2);
+    if direct_link > 0:
+        raise Exception("Unexpected frames through direct link")
+    idirect_link = wt.get_tdls_counter("invalid_direct_link", bssid, addr1,
+                                       addr2);
+    if idirect_link > 0:
+        raise Exception("Unexpected frames through direct link (invalid)")
+    dev[2].remove_group()
+    dev[1].remove_group()
+    dev[0].remove_group()
diff --git a/tests/hwsim/test_p2p_discovery.py b/tests/hwsim/test_p2p_discovery.py
new file mode 100644 (file)
index 0000000..f1029c8
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+#
+# P2P device discovery test cases
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger(__name__)
+
+import hwsim_utils
+
+def test_discovery(dev):
+    """P2P device discovery and provision discovery"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    logger.info("Start device discovery")
+    dev[0].p2p_find(social=True)
+    if not dev[1].discover_peer(addr0):
+        raise Exception("Device discovery timed out")
+    if not dev[0].discover_peer(addr1):
+        raise Exception("Device discovery timed out")
+
+    logger.info("Test provision discovery for display")
+    dev[0].global_request("P2P_PROV_DISC " + addr1 + " display")
+    ev1 = dev[1].wait_global_event(["P2P-PROV-DISC-SHOW-PIN"], timeout=15)
+    if ev1 is None:
+        raise Exception("Provision discovery timed out (display/dev1)")
+    if addr0 not in ev1:
+        raise Exception("Dev0 not in provision discovery event")
+    ev0 = dev[0].wait_global_event(["P2P-PROV-DISC-ENTER-PIN",
+                                    "P2P-PROV-DISC-FAILURE"], timeout=15)
+    if ev0 is None:
+        raise Exception("Provision discovery timed out (display/dev0)")
+    if "P2P-PROV-DISC-FAILURE" in ev0:
+        raise Exception("Provision discovery failed (display/dev0)")
+    if addr1 not in ev0:
+        raise Exception("Dev1 not in provision discovery event")
+
+    logger.info("Test provision discovery for keypad")
+    dev[0].global_request("P2P_PROV_DISC " + addr1 + " keypad")
+    ev1 = dev[1].wait_global_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=15)
+    if ev1 is None:
+        raise Exception("Provision discovery timed out (keypad/dev1)")
+    if addr0 not in ev1:
+        raise Exception("Dev0 not in provision discovery event")
+    ev0 = dev[0].wait_global_event(["P2P-PROV-DISC-SHOW-PIN",
+                                    "P2P-PROV-DISC-FAILURE"],
+                                   timeout=15)
+    if ev0 is None:
+        raise Exception("Provision discovery timed out (keypad/dev0)")
+    if "P2P-PROV-DISC-FAILURE" in ev0:
+        raise Exception("Provision discovery failed (keypad/dev0)")
+    if addr1 not in ev0:
+        raise Exception("Dev1 not in provision discovery event")
+
+    logger.info("Test provision discovery for push button")
+    dev[0].global_request("P2P_PROV_DISC " + addr1 + " pbc")
+    ev1 = dev[1].wait_global_event(["P2P-PROV-DISC-PBC-REQ"], timeout=15)
+    if ev1 is None:
+        raise Exception("Provision discovery timed out (pbc/dev1)")
+    if addr0 not in ev1:
+        raise Exception("Dev0 not in provision discovery event")
+    ev0 = dev[0].wait_global_event(["P2P-PROV-DISC-PBC-RESP",
+                                    "P2P-PROV-DISC-FAILURE"],
+                                   timeout=15)
+    if ev0 is None:
+        raise Exception("Provision discovery timed out (pbc/dev0)")
+    if "P2P-PROV-DISC-FAILURE" in ev0:
+        raise Exception("Provision discovery failed (pbc/dev0)")
+    if addr1 not in ev0:
+        raise Exception("Dev1 not in provision discovery event")
+
+    dev[0].p2p_stop_find
+    dev[1].p2p_stop_find
+
+def test_discovery_group_client(dev):
+    """P2P device discovery for a client in a group"""
+    logger.info("Start autonomous GO " + dev[0].ifname)
+    res = dev[0].p2p_start_go(freq="2422")
+    logger.debug("res: " + str(res))
+    logger.info("Connect a client to the GO")
+    pin = dev[1].wps_read_pin()
+    dev[0].p2p_go_authorize_client(pin)
+    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
+    logger.info("Client connected")
+    hwsim_utils.test_connectivity_p2p(dev[0], dev[1])
+    logger.info("Try to discover a P2P client in a group")
+    if not dev[2].discover_peer(dev[1].p2p_dev_addr(), social=False):
+        raise Exception("Could not discover group client")
diff --git a/tests/hwsim/test_p2p_grpform.py b/tests/hwsim/test_p2p_grpform.py
new file mode 100644 (file)
index 0000000..6bba55b
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/python
+#
+# P2P group formation test cases
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger(__name__)
+import time
+import threading
+import Queue
+
+import hwsim_utils
+
+def check_grpform_results(i_res, r_res):
+    if i_res['result'] != 'success' or r_res['result'] != 'success':
+        raise Exception("Failed group formation")
+    if i_res['ssid'] != r_res['ssid']:
+        raise Exception("SSID mismatch")
+    if i_res['freq'] != r_res['freq']:
+        raise Exception("SSID mismatch")
+    if i_res['go_dev_addr'] != r_res['go_dev_addr']:
+        raise Exception("GO Device Address mismatch")
+
+def go_neg_init(i_dev, r_dev, pin, i_method, i_intent, res):
+    logger.debug("Initiate GO Negotiation from i_dev")
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=15, go_intent=i_intent)
+    logger.debug("i_res: " + str(i_res))
+    res.put(i_res)
+
+def go_neg_pin(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display'):
+    r_dev.p2p_listen()
+    i_dev.p2p_listen()
+    pin = r_dev.wps_read_pin()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.dump_monitor()
+    res = Queue.Queue()
+    t = threading.Thread(target=go_neg_init, args=(i_dev, r_dev, pin, i_method, i_intent, res))
+    t.start()
+    logger.debug("Wait for GO Negotiation Request on r_dev")
+    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("GO Negotiation timed out")
+    r_dev.dump_monitor()
+    logger.debug("Re-initiate GO Negotiation from r_dev")
+    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), pin, r_method, go_intent=r_intent, timeout=15)
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    t.join()
+    i_res = res.get()
+    logger.debug("i_res: " + str(i_res))
+    logger.info("Group formed")
+    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    i_dev.dump_monitor()
+
+def go_neg_pin_authorized(i_dev, r_dev, i_intent=None, r_intent=None, expect_failure=False, i_go_neg_status=None, i_method='enter', r_method='display'):
+    r_dev.p2p_listen()
+    i_dev.p2p_listen()
+    pin = r_dev.wps_read_pin()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method, go_intent=r_intent)
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=15, go_intent=i_intent, expect_failure=expect_failure)
+    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    i_dev.dump_monitor()
+    if i_go_neg_status:
+        if i_res['result'] != 'go-neg-failed':
+            raise Exception("Expected GO Negotiation failure not reported")
+        if i_res['status'] != i_go_neg_status:
+            raise Exception("Expected GO Negotiation status not seen")
+    if expect_failure:
+        return
+    logger.info("Group formed")
+    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+
+def go_neg_init_pbc(i_dev, r_dev, i_intent, res):
+    logger.debug("Initiate GO Negotiation from i_dev")
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=15, go_intent=i_intent)
+    logger.debug("i_res: " + str(i_res))
+    res.put(i_res)
+
+def go_neg_pbc(i_dev, r_dev, i_intent=None, r_intent=None):
+    r_dev.p2p_find(social=True)
+    i_dev.p2p_find(social=True)
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.dump_monitor()
+    res = Queue.Queue()
+    t = threading.Thread(target=go_neg_init_pbc, args=(i_dev, r_dev, i_intent, res))
+    t.start()
+    logger.debug("Wait for GO Negotiation Request on r_dev")
+    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("GO Negotiation timed out")
+    r_dev.dump_monitor()
+    logger.debug("Re-initiate GO Negotiation from r_dev")
+    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), None, "pbc", go_intent=r_intent, timeout=15)
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    t.join()
+    i_res = res.get()
+    logger.debug("i_res: " + str(i_res))
+    logger.info("Group formed")
+    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    i_dev.dump_monitor()
+    return [i_res, r_res]
+
+def test_grpform(dev):
+    """P2P group formation using PIN and authorized connection (init -> GO)"""
+    go_neg_pin_authorized(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
+    dev[0].remove_group()
+    try:
+        dev[1].remove_group()
+    except:
+        pass
+
+def test_grpform2(dev):
+    """P2P group formation using PIN and authorized connection (resp -> GO)"""
+    go_neg_pin_authorized(i_dev=dev[0], i_intent=0, r_dev=dev[1], r_intent=15)
+    dev[0].remove_group()
+    try:
+        dev[1].remove_group()
+    except:
+        pass
+
+def test_grpform3(dev):
+    """P2P group formation using PIN and re-init GO Negotiation"""
+    go_neg_pin(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
+    dev[0].remove_group()
+    try:
+        dev[1].remove_group()
+    except:
+        pass
+
+def test_grpform_pbc(dev):
+    """P2P group formation using PBC and re-init GO Negotiation"""
+    [i_res, r_res] = go_neg_pbc(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
+    check_grpform_results(i_res, r_res)
+    if i_res['role'] != 'GO' or r_res['role'] != 'client':
+        raise Exception("Unexpected device roles")
+    dev[0].remove_group()
+    try:
+        dev[1].remove_group()
+    except:
+        pass
+
+def test_both_go_intent_15(dev):
+    """P2P GO Negotiation with both devices using GO intent 15"""
+    go_neg_pin_authorized(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=15, expect_failure=True, i_go_neg_status=9)
+
+def test_both_go_neg_display(dev):
+    """P2P GO Negotiation with both devices trying to display PIN"""
+    go_neg_pin_authorized(i_dev=dev[0], r_dev=dev[1], expect_failure=True, i_go_neg_status=10, i_method='display', r_method='display')
+
+def test_both_go_neg_enter(dev):
+    """P2P GO Negotiation with both devices trying to enter PIN"""
+    go_neg_pin_authorized(i_dev=dev[0], r_dev=dev[1], expect_failure=True, i_go_neg_status=10, i_method='enter', r_method='enter')
diff --git a/tests/hwsim/wlantest.py b/tests/hwsim/wlantest.py
new file mode 100644 (file)
index 0000000..cf7c9fb
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+#
+# Python class for controlling wlantest
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import time
+import subprocess
+import logging
+import wpaspy
+
+logger = logging.getLogger(__name__)
+
+class Wlantest:
+    def __init__(self):
+        if os.path.isfile('../../wlantest/wlantest_cli'):
+            self.wlantest_cli = '../../wlantest/wlantest_cli'
+        else:
+            self.wlantest_cli = 'wlantest_cli'
+
+    def flush(self):
+        res = subprocess.check_output([self.wlantest_cli, "flush"])
+        if "FAIL" in res:
+            raise Exception("wlantest_cli flush failed")
+
+    def add_passphrase(self, passphrase):
+        res = subprocess.check_output([self.wlantest_cli, "add_passphrase",
+                                       passphrase])
+        if "FAIL" in res:
+            raise Exception("wlantest_cli add_passphrase failed")
+
+    def add_wepkey(self, key):
+        res = subprocess.check_output([self.wlantest_cli, "add_wepkey", key])
+        if "FAIL" in res:
+            raise Exception("wlantest_cli add_key failed")
+
+    def info_bss(self, field, bssid):
+        res = subprocess.check_output([self.wlantest_cli, "info_bss",
+                                       field, bssid])
+        if "FAIL" in res:
+            raise Exception("Could not get BSS info from wlantest for " + bssid)
+        return res
+
+    def info_sta(self, field, bssid, addr):
+        res = subprocess.check_output([self.wlantest_cli, "info_sta",
+                                       field, bssid, addr])
+        if "FAIL" in res:
+            raise Exception("Could not get STA info from wlantest for " + addr)
+        return res
+
+    def get_sta_counter(self, field, bssid, addr):
+        res = subprocess.check_output([self.wlantest_cli, "get_sta_counter",
+                                       field, bssid, addr]);
+        if "FAIL" in res:
+            raise Exception("wlantest_cli command failed")
+        return int(res)
+
+    def tdls_clear(self, bssid, addr1, addr2):
+        subprocess.call([self.wlantest_cli, "clear_tdls_counters", bssid, addr1,
+                         addr2]);
+
+    def get_tdls_counter(self, field, bssid, addr1, addr2):
+        res = subprocess.check_output([self.wlantest_cli, "get_tdls_counter",
+                                       field, bssid, addr1, addr2]);
+        if "FAIL" in res:
+            raise Exception("wlantest_cli command failed")
+        return int(res)
+
+    def require_ap_pmf_mandatory(self, bssid):
+        res = self.info_bss("rsn_capab", bssid)
+        if "MFPR" not in res:
+            raise Exception("AP did not require PMF")
+        if "MFPC" not in res:
+            raise Exception("AP did not enable PMF")
+        res = self.info_bss("key_mgmt", bssid)
+        if "PSK-SHA256" not in res:
+            raise Exception("AP did not enable SHA256-based AKM for PMF")
+
+    def require_ap_pmf_optional(self, bssid):
+        res = self.info_bss("rsn_capab", bssid)
+        if "MFPR" in res:
+            raise Exception("AP required PMF")
+        if "MFPC" not in res:
+            raise Exception("AP did not enable PMF")
+
+    def require_ap_no_pmf(self, bssid):
+        res = self.info_bss("rsn_capab", bssid)
+        if "MFPR" in res:
+            raise Exception("AP required PMF")
+        if "MFPC" in res:
+            raise Exception("AP enabled PMF")
+
+    def require_sta_pmf_mandatory(self, bssid, addr):
+        res = self.info_sta("rsn_capab", bssid, addr)
+        if "MFPR" not in res:
+            raise Exception("STA did not require PMF")
+        if "MFPC" not in res:
+            raise Exception("STA did not enable PMF")
+
+    def require_sta_pmf(self, bssid, addr):
+        res = self.info_sta("rsn_capab", bssid, addr)
+        if "MFPC" not in res:
+            raise Exception("STA did not enable PMF")
+
+    def require_sta_key_mgmt(self, bssid, addr, key_mgmt):
+        res = self.info_sta("key_mgmt", bssid, addr)
+        if key_mgmt not in res:
+            raise Exception("Unexpected STA key_mgmt")
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
new file mode 100644 (file)
index 0000000..3e8036e
--- /dev/null
@@ -0,0 +1,422 @@
+#!/usr/bin/python
+#
+# Python class for controlling wpa_supplicant
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import time
+import logging
+import re
+import wpaspy
+
+logger = logging.getLogger(__name__)
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+class WpaSupplicant:
+    def __init__(self, ifname, global_iface=None):
+        self.ifname = ifname
+        self.group_ifname = None
+        self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
+        self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
+        self.mon.attach()
+
+        self.global_iface = global_iface
+        if global_iface:
+            self.global_ctrl = wpaspy.Ctrl(global_iface)
+            self.global_mon = wpaspy.Ctrl(global_iface)
+            self.global_mon.attach()
+
+    def request(self, cmd):
+        logger.debug(self.ifname + ": CTRL: " + cmd)
+        return self.ctrl.request(cmd)
+
+    def global_request(self, cmd):
+        if self.global_iface is None:
+            self.request(cmd)
+        else:
+            logger.debug(self.ifname + ": CTRL: " + cmd)
+            return self.global_ctrl.request(cmd)
+
+    def group_request(self, cmd):
+        if self.group_ifname and self.group_ifname != self.ifname:
+            logger.debug(self.group_ifname + ": CTRL: " + cmd)
+            gctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
+            return gctrl.request(cmd)
+        return self.request(cmd)
+
+    def ping(self):
+        return "PONG" in self.request("PING")
+
+    def reset(self):
+        self.request("FLUSH")
+        self.request("SET ignore_old_scan_res 0")
+        self.group_ifname = None
+        self.dump_monitor()
+
+    def add_network(self):
+        id = self.request("ADD_NETWORK")
+        if "FAIL" in id:
+            raise Exception("ADD_NETWORK failed")
+        return int(id)
+
+    def remove_network(self, id):
+        id = self.request("REMOVE_NETWORK " + str(id))
+        if "FAIL" in id:
+            raise Exception("REMOVE_NETWORK failed")
+        return None
+
+    def set_network(self, id, field, value):
+        res = self.request("SET_NETWORK " + str(id) + " " + field + " " + value)
+        if "FAIL" in res:
+            raise Exception("SET_NETWORK failed")
+        return None
+
+    def set_network_quoted(self, id, field, value):
+        res = self.request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
+        if "FAIL" in res:
+            raise Exception("SET_NETWORK failed")
+        return None
+
+    def add_cred(self):
+        id = self.request("ADD_CRED")
+        if "FAIL" in id:
+            raise Exception("ADD_CRED failed")
+        return int(id)
+
+    def remove_cred(self, id):
+        id = self.request("REMOVE_CRED " + str(id))
+        if "FAIL" in id:
+            raise Exception("REMOVE_CRED failed")
+        return None
+
+    def set_cred(self, id, field, value):
+        res = self.request("SET_CRED " + str(id) + " " + field + " " + value)
+        if "FAIL" in res:
+            raise Exception("SET_CRED failed")
+        return None
+
+    def set_cred_quoted(self, id, field, value):
+        res = self.request("SET_CRED " + str(id) + " " + field + ' "' + value + '"')
+        if "FAIL" in res:
+            raise Exception("SET_CRED failed")
+        return None
+
+    def select_network(self, id):
+        id = self.request("SELECT_NETWORK " + str(id))
+        if "FAIL" in id:
+            raise Exception("SELECT_NETWORK failed")
+        return None
+
+    def connect_network(self, id):
+        self.dump_monitor()
+        self.select_network(id)
+        ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
+        if ev is None:
+            raise Exception("Association with the AP timed out")
+        self.dump_monitor()
+
+    def get_status(self):
+        res = self.request("STATUS")
+        lines = res.splitlines()
+        vals = dict()
+        for l in lines:
+            [name,value] = l.split('=', 1)
+            vals[name] = value
+        return vals
+
+    def get_status_field(self, field):
+        vals = self.get_status()
+        if field in vals:
+            return vals[field]
+        return None
+
+    def get_group_status(self):
+        res = self.group_request("STATUS")
+        lines = res.splitlines()
+        vals = dict()
+        for l in lines:
+            [name,value] = l.split('=', 1)
+            vals[name] = value
+        return vals
+
+    def get_group_status_field(self, field):
+        vals = self.get_group_status()
+        if field in vals:
+            return vals[field]
+        return None
+
+    def p2p_dev_addr(self):
+        return self.get_status_field("p2p_device_address")
+
+    def p2p_interface_addr(self):
+        return self.get_group_status_field("address")
+
+    def p2p_listen(self):
+        return self.global_request("P2P_LISTEN")
+
+    def p2p_find(self, social=False):
+        if social:
+            return self.global_request("P2P_FIND type=social")
+        return self.global_request("P2P_FIND")
+
+    def p2p_stop_find(self):
+        return self.global_request("P2P_STOP_FIND")
+
+    def wps_read_pin(self):
+        #TODO: make this random
+        self.pin = "12345670"
+        return self.pin
+
+    def peer_known(self, peer, full=True):
+        res = self.global_request("P2P_PEER " + peer)
+        if peer.lower() not in res.lower():
+            return False
+        if not full:
+            return True
+        return "[PROBE_REQ_ONLY]" not in res
+
+    def discover_peer(self, peer, full=True, timeout=15, social=True):
+        logger.info(self.ifname + ": Trying to discover peer " + peer)
+        if self.peer_known(peer, full):
+            return True
+        self.p2p_find(social)
+        count = 0
+        while count < timeout:
+            time.sleep(1)
+            count = count + 1
+            if self.peer_known(peer, full):
+                return True
+        return False
+
+    def group_form_result(self, ev, expect_failure=False):
+        if expect_failure:
+            if "P2P-GROUP-STARTED" in ev:
+                raise Exception("Group formation succeeded when expecting failure")
+            exp = r'<.>(P2P-GO-NEG-FAILURE) status=([0-9]*)'
+            s = re.split(exp, ev)
+            if len(s) < 3:
+                return None
+            res = {}
+            res['result'] = 'go-neg-failed'
+            res['status'] = int(s[2])
+            return res
+
+        if "P2P-GROUP-STARTED" not in ev:
+            raise Exception("No P2P-GROUP-STARTED event seen")
+
+        exp = r'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*)'
+        s = re.split(exp, ev)
+        if len(s) < 8:
+            raise Exception("Could not parse P2P-GROUP-STARTED")
+        res = {}
+        res['result'] = 'success'
+        res['ifname'] = s[2]
+        self.group_ifname = s[2]
+        res['role'] = s[3]
+        res['ssid'] = s[4]
+        res['freq'] = s[5]
+        p = re.match(r'psk=([0-9a-f]*)', s[6])
+        if p:
+            res['psk'] = p.group(1)
+        p = re.match(r'passphrase="(.*)"', s[6])
+        if p:
+            res['passphrase'] = p.group(1)
+        res['go_dev_addr'] = s[7]
+        return res
+
+    def p2p_go_neg_auth(self, peer, pin, method, go_intent=None):
+        if not self.discover_peer(peer):
+            raise Exception("Peer " + peer + " not found")
+        self.dump_monitor()
+        cmd = "P2P_CONNECT " + peer + " " + pin + " " + method + " auth"
+        if go_intent:
+            cmd = cmd + ' go_intent=' + str(go_intent)
+        if "OK" in self.global_request(cmd):
+            return None
+        raise Exception("P2P_CONNECT (auth) failed")
+
+    def p2p_go_neg_auth_result(self, timeout=1, expect_failure=False):
+        ev = self.wait_global_event(["P2P-GROUP-STARTED","P2P-GO-NEG-FAILURE"], timeout);
+        if ev is None:
+            if expect_failure:
+                return None
+            raise Exception("Group formation timed out")
+        self.dump_monitor()
+        return self.group_form_result(ev, expect_failure)
+
+    def p2p_go_neg_init(self, peer, pin, method, timeout=0, go_intent=None, expect_failure=False):
+        if not self.discover_peer(peer):
+            raise Exception("Peer " + peer + " not found")
+        self.dump_monitor()
+        if pin:
+            cmd = "P2P_CONNECT " + peer + " " + pin + " " + method
+        else:
+            cmd = "P2P_CONNECT " + peer + " " + method
+        if go_intent:
+            cmd = cmd + ' go_intent=' + str(go_intent)
+        if "OK" in self.global_request(cmd):
+            if timeout == 0:
+                self.dump_monitor()
+                return None
+            ev = self.wait_global_event(["P2P-GROUP-STARTED","P2P-GO-NEG-FAILURE"], timeout)
+            if ev is None:
+                if expect_failure:
+                    return None
+                raise Exception("Group formation timed out")
+            self.dump_monitor()
+            return self.group_form_result(ev, expect_failure)
+        raise Exception("P2P_CONNECT failed")
+
+    def wait_event(self, events, timeout):
+        count = 0
+        while count < timeout * 10:
+            count = count + 1
+            time.sleep(0.1)
+            while self.mon.pending():
+                ev = self.mon.recv()
+                logger.debug(self.ifname + ": " + ev)
+                for event in events:
+                    if event in ev:
+                        return ev
+        return None
+
+    def wait_global_event(self, events, timeout):
+        if self.global_iface is None:
+            self.wait_event(events, timeout)
+        else:
+            count = 0
+            while count < timeout * 10:
+                count = count + 1
+                time.sleep(0.1)
+                while self.global_mon.pending():
+                    ev = self.global_mon.recv()
+                    logger.debug(self.ifname + ": " + ev)
+                    for event in events:
+                        if event in ev:
+                            return ev
+        return None
+
+    def dump_monitor(self):
+        while self.mon.pending():
+            ev = self.mon.recv()
+            logger.debug(self.ifname + ": " + ev)
+
+    def remove_group(self, ifname=None):
+        if ifname is None:
+            ifname = self.group_ifname if self.group_ifname else self.iname
+        if "OK" not in self.global_request("P2P_GROUP_REMOVE " + ifname):
+            raise Exception("Group could not be removed")
+        self.group_ifname = None
+
+    def p2p_start_go(self, persistent=None, freq=None):
+        self.dump_monitor()
+        cmd = "P2P_GROUP_ADD"
+        if persistent is None:
+            pass
+        elif persistent is True:
+            cmd = cmd + " persistent"
+        else:
+            cmd = cmd + " persistent=" + str(persistent)
+        if freq:
+            cmd = cmd + " freq=" + freq
+        if "OK" in self.global_request(cmd):
+            ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
+            if ev is None:
+                raise Exception("GO start up timed out")
+            self.dump_monitor()
+            return self.group_form_result(ev)
+        raise Exception("P2P_GROUP_ADD failed")
+
+    def p2p_go_authorize_client(self, pin):
+        cmd = "WPS_PIN any " + pin
+        if "FAIL" in self.group_request(cmd):
+            raise Exception("Failed to authorize client connection on GO")
+        return None
+
+    def p2p_connect_group(self, go_addr, pin, timeout=0):
+        self.dump_monitor()
+        if not self.discover_peer(go_addr, social=False):
+            raise Exception("GO " + go_addr + " not found")
+        self.dump_monitor()
+        cmd = "P2P_CONNECT " + go_addr + " " + pin + " join"
+        if "OK" in self.global_request(cmd):
+            if timeout == 0:
+                self.dump_monitor()
+                return None
+            ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
+            if ev is None:
+                raise Exception("Joining the group timed out")
+            self.dump_monitor()
+            return self.group_form_result(ev)
+        raise Exception("P2P_CONNECT(join) failed")
+
+    def tdls_setup(self, peer):
+        cmd = "TDLS_SETUP " + peer
+        if "FAIL" in self.group_request(cmd):
+            raise Exception("Failed to request TDLS setup")
+        return None
+
+    def tdls_teardown(self, peer):
+        cmd = "TDLS_TEARDOWN " + peer
+        if "FAIL" in self.group_request(cmd):
+            raise Exception("Failed to request TDLS teardown")
+        return None
+
+    def connect(self, ssid, psk=None, proto=None, key_mgmt=None, wep_key0=None, ieee80211w=None):
+        logger.info("Connect STA " + self.ifname + " to AP")
+        id = self.add_network()
+        self.set_network_quoted(id, "ssid", ssid)
+        if psk:
+            self.set_network_quoted(id, "psk", psk)
+        if proto:
+            self.set_network(id, "proto", proto)
+        if key_mgmt:
+            self.set_network(id, "key_mgmt", key_mgmt)
+        if ieee80211w:
+            self.set_network(id, "ieee80211w", ieee80211w)
+        if wep_key0:
+            self.set_network(id, "wep_key0", wep_key0)
+        self.connect_network(id)
+
+    def scan(self, type=None):
+        if type:
+            cmd = "SCAN TYPE=" + type
+        else:
+            cmd = "SCAN"
+        self.dump_monitor()
+        if not "OK" in self.request(cmd):
+            raise Exception("Failed to trigger scan")
+        ev = self.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
+        if ev is None:
+            raise Exception("Scan timed out")
+
+    def roam(self, bssid):
+        self.dump_monitor()
+        self.request("ROAM " + bssid)
+        ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
+        if ev is None:
+            raise Exception("Roaming with the AP timed out")
+        self.dump_monitor()
+
+    def wps_reg(self, bssid, pin, new_ssid=None, key_mgmt=None, cipher=None,
+                new_passphrase=None):
+        self.dump_monitor()
+        if new_ssid:
+            self.request("WPS_REG " + bssid + " " + pin + " " +
+                         new_ssid.encode("hex") + " " + key_mgmt + " " +
+                         cipher + " " + new_passphrase.encode("hex"))
+            ev = self.wait_event(["WPS-SUCCESS"], timeout=15)
+        else:
+            self.request("WPS_REG " + bssid + " " + pin)
+            ev = self.wait_event(["WPS-CRED-RECEIVED"], timeout=15)
+            if ev is None:
+                raise Exception("WPS cred timed out")
+            ev = self.wait_event(["WPS-FAIL"], timeout=15)
+        if ev is None:
+            raise Exception("WPS timed out")
+        ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
+        if ev is None:
+            raise Exception("Association with the AP timed out")
index f596a1e..84c959c 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Test program for AES
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -166,6 +160,284 @@ static int test_cbc(void)
 }
 
 
+/*
+ * GCM test vectors from
+ * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+ */
+struct gcm_test_vector {
+       char *k;
+       char *p;
+       char *aad;
+       char *iv;
+       char *c;
+       char *t;
+};
+
+static const struct gcm_test_vector gcm_tests[] = {
+       {
+               /* Test Case 1 */
+               "00000000000000000000000000000000",
+               "",
+               "",
+               "000000000000000000000000",
+               "",
+               "58e2fccefa7e3061367f1d57a4e7455a"
+       },
+       {
+               /* Test Case 2 */
+               "00000000000000000000000000000000",
+               "00000000000000000000000000000000",
+               "",
+               "000000000000000000000000",
+               "0388dace60b6a392f328c2b971b2fe78",
+               "ab6e47d42cec13bdf53a67b21257bddf"
+       },
+       {
+               /* Test Case 3 */
+               "feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+               "",
+               "cafebabefacedbaddecaf888",
+               "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+               "4d5c2af327cd64a62cf35abd2ba6fab4"
+       },
+       {
+               /* Test Case 4 */
+               "feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbaddecaf888",
+               "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+               "5bc94fbc3221a5db94fae95ae7121a47"
+       },
+       {
+               /* Test Case 5 */
+               "feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbad",
+               "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+               "3612d2e79e3b0785561be14aaca2fccb"
+       },
+       {
+               /* Test Case 6 */
+               "feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+               "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+               "619cc5aefffe0bfa462af43c1699d050"
+       },
+       {
+               /* Test Case 7 */
+               "000000000000000000000000000000000000000000000000",
+               "",
+               "",
+               "000000000000000000000000",
+               "",
+               "cd33b28ac773f74ba00ed1f312572435"
+       },
+       {
+               /* Test Case 8 */
+               "000000000000000000000000000000000000000000000000",
+               "00000000000000000000000000000000",
+               "",
+               "000000000000000000000000",
+               "98e7247c07f0fe411c267e4384b0f600",
+               "2ff58d80033927ab8ef4d4587514f0fb"
+       },
+       {
+               /* Test Case 9 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+               "",
+               "cafebabefacedbaddecaf888",
+               "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+               "9924a7c8587336bfb118024db8674a14"
+       },
+       {
+               /* Test Case 10 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbaddecaf888",
+               "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+               "2519498e80f1478f37ba55bd6d27618c"
+       },
+       {
+               /* Test Case 11 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbad",
+               "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+               "65dcc57fcf623a24094fcca40d3533f8"
+       },
+       {
+               /* Test Case 12 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+               "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+               "dcf566ff291c25bbb8568fc3d376a6d9"
+       },
+       {
+               /* Test Case 13 */
+               "0000000000000000000000000000000000000000000000000000000000000000",
+               "",
+               "",
+               "000000000000000000000000",
+               "",
+               "530f8afbc74536b9a963b4f1c4cb738b"
+       },
+       {
+               /* Test Case 14 */
+               "0000000000000000000000000000000000000000000000000000000000000000",
+               "00000000000000000000000000000000",
+               "",
+               "000000000000000000000000",
+               "cea7403d4d606b6e074ec5d3baf39d18",
+               "d0d1c8a799996bf0265b98b5d48ab919"
+       },
+       {
+               /* Test Case 15 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+               "",
+               "cafebabefacedbaddecaf888",
+               "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+               "b094dac5d93471bdec1a502270e3cc6c"
+       },
+       {
+               /* Test Case 16 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbaddecaf888",
+               "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+               "76fc6ece0f4e1768cddf8853bb2d551b"
+       },
+       {
+               /* Test Case 17 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "cafebabefacedbad",
+               "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+               "3a337dbf46a792c45e454913fe2ea8f2"
+       },
+       {
+               /* Test Case 18 */
+               "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+               "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+               "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+               "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+               "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+               "a44a8266ee1c8eb0c8b5d4cf5ae9f19a"
+       }
+};
+
+
+static int test_gcm(void)
+{
+       int ret = 0;
+       int i;
+       u8 k[32], aad[32], iv[64], t[16], tag[16];
+       u8 p[64], c[64], tmp[64];
+       size_t k_len, p_len, aad_len, iv_len;
+
+       for (i = 0; i < sizeof(gcm_tests) / sizeof(gcm_tests[0]); i++) {
+               const struct gcm_test_vector *tc = &gcm_tests[i];
+
+               k_len = os_strlen(tc->k) / 2;
+               if (hexstr2bin(tc->k, k, k_len)) {
+                       printf("Invalid GCM test vector %d (k)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               p_len = os_strlen(tc->p) / 2;
+               if (hexstr2bin(tc->p, p, p_len)) {
+                       printf("Invalid GCM test vector %d (p)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               aad_len = os_strlen(tc->aad) / 2;
+               if (hexstr2bin(tc->aad, aad, aad_len)) {
+                       printf("Invalid GCM test vector %d (aad)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               iv_len = os_strlen(tc->iv) / 2;
+               if (hexstr2bin(tc->iv, iv, iv_len)) {
+                       printf("Invalid GCM test vector %d (iv)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               if (hexstr2bin(tc->c, c, p_len)) {
+                       printf("Invalid GCM test vector %d (c)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               if (hexstr2bin(tc->t, t, sizeof(t))) {
+                       printf("Invalid GCM test vector %d (t)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               if (aes_gcm_ae(k, k_len, iv, iv_len, p, p_len, aad, aad_len,
+                              tmp, tag) < 0) {
+                       printf("GCM-AE failed (test case %d)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               if (os_memcmp(c, tmp, p_len) != 0) {
+                       printf("GCM-AE mismatch (test case %d)\n", i);
+                       ret++;
+               }
+
+               if (os_memcmp(tag, t, sizeof(tag)) != 0) {
+                       printf("GCM-AE tag mismatch (test case %d)\n", i);
+                       ret++;
+               }
+
+               if (p_len == 0) {
+                       if (aes_gmac(k, k_len, iv, iv_len, aad, aad_len, tag) <
+                           0) {
+                               printf("GMAC failed (test case %d)\n", i);
+                               ret++;
+                               continue;
+                       }
+
+                       if (os_memcmp(tag, t, sizeof(tag)) != 0) {
+                               printf("GMAC tag mismatch (test case %d)\n", i);
+                               ret++;
+                       }
+               }
+
+               if (aes_gcm_ad(k, k_len, iv, iv_len, c, p_len, aad, aad_len,
+                              t, tmp) < 0) {
+                       printf("GCM-AD failed (test case %d)\n", i);
+                       ret++;
+                       continue;
+               }
+
+               if (os_memcmp(p, tmp, p_len) != 0) {
+                       printf("GCM-AD mismatch (test case %d)\n", i);
+                       ret++;
+               }
+       }
+
+       return ret;
+}
+
+
 /* OMAC1 AES-128 test vectors from
  * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
  * which are same as the examples from NIST SP800-38B
@@ -301,6 +573,8 @@ int main(int argc, char *argv[])
 
        ret += test_cbc();
 
+       ret += test_gcm();
+
        if (ret)
                printf("FAILED!\n");
 
index e59aa49..7b6f7be 100644 (file)
@@ -2,14 +2,8 @@
  * Testing tool for ASN.1 routines
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 747290e..980febf 100644 (file)
@@ -2,14 +2,8 @@
  * Base64 encoding/decoding (RFC1341) - test program
  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
diff --git a/tests/test-bitfield.c b/tests/test-bitfield.c
new file mode 100644 (file)
index 0000000..aff1790
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * bitfield unit tests
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/bitfield.h"
+
+int main(int argc, char *argv[])
+{
+       struct bitfield *bf;
+       int i;
+       int errors = 0;
+
+       bf = bitfield_alloc(123);
+       if (bf == NULL)
+               return -1;
+
+       for (i = 0; i < 123; i++) {
+               if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+                       errors++;
+               if (i > 0 && bitfield_is_set(bf, i - 1))
+                       errors++;
+               bitfield_set(bf, i);
+               if (!bitfield_is_set(bf, i))
+                       errors++;
+               bitfield_clear(bf, i);
+               if (bitfield_is_set(bf, i))
+                       errors++;
+       }
+
+       for (i = 123; i < 200; i++) {
+               if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+                       errors++;
+               if (i > 0 && bitfield_is_set(bf, i - 1))
+                       errors++;
+               bitfield_set(bf, i);
+               if (bitfield_is_set(bf, i))
+                       errors++;
+               bitfield_clear(bf, i);
+               if (bitfield_is_set(bf, i))
+                       errors++;
+       }
+
+       for (i = 0; i < 123; i++) {
+               if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+                       errors++;
+               bitfield_set(bf, i);
+               if (!bitfield_is_set(bf, i))
+                       errors++;
+       }
+
+       for (i = 0; i < 123; i++) {
+               if (!bitfield_is_set(bf, i))
+                       errors++;
+               bitfield_clear(bf, i);
+               if (bitfield_is_set(bf, i))
+                       errors++;
+       }
+
+       for (i = 0; i < 123; i++) {
+               if (bitfield_get_first_zero(bf) != i)
+                       errors++;
+               bitfield_set(bf, i);
+       }
+       if (bitfield_get_first_zero(bf) != -1)
+               errors++;
+       for (i = 0; i < 123; i++) {
+               if (!bitfield_is_set(bf, i))
+                       errors++;
+               bitfield_clear(bf, i);
+               if (bitfield_get_first_zero(bf) != i)
+                       errors++;
+               bitfield_set(bf, i);
+       }
+       if (bitfield_get_first_zero(bf) != -1)
+               errors++;
+
+       bitfield_free(bf);
+
+       if (errors) {
+               printf("%d test(s) failed\n", errors);
+               return -1;
+       }
+
+       return 0;
+}
index 96e894d..2f41500 100644 (file)
@@ -2,14 +2,8 @@
  * Testing tool for TLSv1 client routines using HTTPS
  * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 930ce41..01bcbf6 100644 (file)
@@ -2,14 +2,8 @@
  * Doubly-linked list - test program
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index e390d0f..903fd10 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for MD4 (test vectors from RFC 1320)
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index c33f1c2..5ae0671 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for MD5 (test vectors from RFC 1321)
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index ae36171..b740bc9 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for ms_funcs
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "crypto/ms_funcs.c"
diff --git a/tests/test-printf.c b/tests/test-printf.c
new file mode 100644 (file)
index 0000000..a8a2e25
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * printf format routines - test program
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/common.h"
+
+
+struct test_data {
+       u8 *data;
+       size_t len;
+       char *encoded;
+};
+
+static const struct test_data tests[] = {
+       { (u8 *) "abcde", 5, "abcde" },
+       { (u8 *) "a\0b\nc\ed\re\tf", 11, "a\\0b\\nc\\ed\\re\\tf" },
+       { (u8 *) "\x00\x31\x00\x32\x00\x39", 6, "\\x001\\0002\\09" },
+       { (u8 *) "\n\n\n", 3, "\n\12\x0a" },
+       { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+         "\\xc3\\xa5\xc3\\xa4\\xc3\\xb6\\xc3\\x85\\xc3\\x84\\xc3\\x96" },
+       { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+         "\\303\\245\\303\\244\\303\\266\\303\\205\\303\\204\\303\\226" },
+       { (u8 *) "\xe5\xe4\xf6\xc5\xc4\xd6", 6,
+         "\\xe5\\xe4\\xf6\\xc5\\xc4\\xd6" },
+       { NULL, 0, NULL }
+};
+
+
+static void print_hex(const u8 *data, size_t len)
+{
+       size_t i;
+       for (i = 0; i < len; i++)
+               printf(" %02x", data[i]);
+}
+
+
+int main(int argc, char *argv[])
+{
+       int i;
+       size_t binlen;
+       char buf[100];
+       u8 bin[100];
+       int errors = 0;
+
+       for (i = 0; tests[i].data; i++) {
+               const struct test_data *test = &tests[i];
+               printf("%d:", i);
+               print_hex(test->data, test->len);
+               printf_encode(buf, sizeof(buf), test->data, test->len);
+               printf(" -> \"%s\"\n", buf);
+
+               binlen = printf_decode(bin, sizeof(bin), buf);
+               if (binlen != test->len ||
+                   os_memcmp(bin, test->data, binlen) != 0) {
+                       printf("Error in decoding#1:");
+                       print_hex(bin, binlen);
+                       printf("\n");
+                       errors++;
+               }
+
+               binlen = printf_decode(bin, sizeof(bin), test->encoded);
+               if (binlen != test->len ||
+                   os_memcmp(bin, test->data, binlen) != 0) {
+                       printf("Error in decoding#2:");
+                       print_hex(bin, binlen);
+                       printf("\n");
+                       errors++;
+               }
+       }
+
+       if (errors) {
+               printf("%d test(s) failed\n", errors);
+               return -1;
+       }
+
+       return 0;
+}
index cbe2aeb..6ac2ef3 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for RC4
  * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 1b390f1..4141c49 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for SHA1 and MD5
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index f194ff9..9d45439 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for SHA256
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 96181c2..e92ea61 100644 (file)
@@ -2,14 +2,8 @@
  * Testing tool for X.509v3 routines
  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 6943efc..1290b5c 100644 (file)
@@ -2,14 +2,8 @@
  * Testing tool for X.509v3 routines
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index c165ed4..6594b34 100644 (file)
@@ -1,4 +1,4 @@
-ALL=wlantest wlantest_cli
+ALL=wlantest wlantest_cli test_vectors
 
 all: $(ALL)
 
@@ -67,9 +67,18 @@ OBJS += tkip.o
 OBJS += ctrl.o
 OBJS += inject.o
 OBJS += wep.o
+OBJS += bip.o
 
 LIBS += -lpcap
 
+TOBJS += test_vectors.o
+TOBJS += crc32.o
+TOBJS += ccmp.o
+TOBJS += tkip.o
+TOBJS += wep.o
+TOBJS += bip.o
+TOBJS += gcmp.o
+
 
 ../src/utils/libutils.a:
        $(MAKE) -C ../src/utils
@@ -104,6 +113,9 @@ wlantest: $(OBJS) $(LIBWLANTEST)
 wlantest_cli: $(OBJS_cli) $(LIBWLANTEST)
        $(LDO) $(LDFLAGS) -o wlantest_cli $(OBJS_cli) -L. -lwlantest
 
+test_vectors: $(TOBJS) $(LIBWLANTEST)
+       $(LDO) $(LDFLAGS) -o test_vectors $(TOBJS) -L. -lwlantest $(LIBS)
+
 clean:
        $(MAKE) -C ../src clean
        rm -f core *~ *.o *.d libwlantest.a libwlantest.so $(ALL)
diff --git a/wlantest/bip.c b/wlantest/bip.c
new file mode 100644 (file)
index 0000000..d9a52e9
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * BIP
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes_wrap.h"
+#include "wlantest.h"
+
+
+u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid,
+                size_t *prot_len)
+{
+       u8 *prot, *pos, *buf;
+       u8 mic[16];
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+       size_t plen;
+
+       plen = len + 18;
+       prot = os_malloc(plen);
+       if (prot == NULL)
+               return NULL;
+       os_memcpy(prot, frame, len);
+       pos = prot + len;
+       *pos++ = WLAN_EID_MMIE;
+       *pos++ = 16;
+       WPA_PUT_LE16(pos, keyid);
+       pos += 2;
+       os_memcpy(pos, ipn, 6);
+       pos += 6;
+       os_memset(pos, 0, 8); /* MIC */
+
+       buf = os_malloc(plen + 20 - 24);
+       if (buf == NULL) {
+               os_free(prot);
+               return NULL;
+       }
+
+       /* BIP AAD: FC(masked) A1 A2 A3 */
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
+       WPA_PUT_LE16(buf, fc);
+       os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
+       os_memcpy(buf + 20, prot + 24, plen - 24);
+       wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
+       /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
+       if (omac1_aes_128(igtk, buf, plen + 20 - 24, mic) < 0) {
+               os_free(prot);
+               os_free(buf);
+               return NULL;
+       }
+       os_free(buf);
+
+       os_memcpy(pos, mic, 8);
+       wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
+
+       *prot_len = plen;
+       return prot;
+}
+
+
+u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
+                     u8 *ipn, int keyid, size_t *prot_len)
+{
+       u8 *prot, *pos, *buf;
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+       size_t plen;
+       u8 nonce[12], *npos;
+
+       plen = len + 26;
+       prot = os_malloc(plen);
+       if (prot == NULL)
+               return NULL;
+       os_memcpy(prot, frame, len);
+       pos = prot + len;
+       *pos++ = WLAN_EID_MMIE;
+       *pos++ = 24;
+       WPA_PUT_LE16(pos, keyid);
+       pos += 2;
+       os_memcpy(pos, ipn, 6);
+       pos += 6;
+       os_memset(pos, 0, 16); /* MIC */
+
+       buf = os_malloc(plen + 20 - 24);
+       if (buf == NULL) {
+               os_free(prot);
+               return NULL;
+       }
+
+       /* BIP AAD: FC(masked) A1 A2 A3 */
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
+       WPA_PUT_LE16(buf, fc);
+       os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
+       os_memcpy(buf + 20, prot + 24, plen - 24);
+       wpa_hexdump(MSG_MSGDUMP, "BIP-GMAC: AAD|Body(masked)",
+                   buf, plen + 20 - 24);
+
+       /* Nonce: A2 | IPN */
+       os_memcpy(nonce, hdr->addr2, ETH_ALEN);
+       npos = nonce + ETH_ALEN;
+       *npos++ = ipn[5];
+       *npos++ = ipn[4];
+       *npos++ = ipn[3];
+       *npos++ = ipn[2];
+       *npos++ = ipn[1];
+       *npos++ = ipn[0];
+       wpa_hexdump(MSG_EXCESSIVE, "BIP-GMAC: Nonce", nonce, sizeof(nonce));
+
+       /* MIC = AES-GMAC(AAD || Frame Body(masked)) */
+       if (aes_gmac(igtk, igtk_len, nonce, sizeof(nonce),
+                    buf, plen + 20 - 24, pos) < 0) {
+               os_free(prot);
+               os_free(buf);
+               return NULL;
+       }
+       os_free(buf);
+
+       wpa_hexdump(MSG_DEBUG, "BIP-GMAC MMIE MIC", pos, 16);
+
+       *prot_len = plen;
+       return prot;
+}
index 34dee50..98d98ef 100644 (file)
@@ -2,14 +2,8 @@
  * BSS list
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -98,7 +92,7 @@ int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
        pmk = os_zalloc(sizeof(*pmk));
        if (pmk == NULL)
                return -1;
-       if (pbkdf2_sha1(passphrase, (char *) bss->ssid, bss->ssid_len, 4096,
+       if (pbkdf2_sha1(passphrase, bss->ssid, bss->ssid_len, 4096,
                        pmk->pmk, sizeof(pmk->pmk)) < 0) {
                os_free(pmk);
                return -1;
@@ -163,8 +157,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
 
        if (elems->rsn_ie == NULL) {
                if (bss->rsnie[0]) {
-                       wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
-                                  MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "BSS " MACSTR
+                                " - RSN IE removed", MAC2STR(bss->bssid));
                        bss->rsnie[0] = 0;
                        update = 1;
                }
@@ -184,8 +178,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
 
        if (elems->wpa_ie == NULL) {
                if (bss->wpaie[0]) {
-                       wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
-                                  MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "BSS " MACSTR
+                                " - WPA IE removed", MAC2STR(bss->bssid));
                        bss->wpaie[0] = 0;
                        update = 1;
                }
@@ -217,8 +211,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
        if (bss->wpaie[0]) {
                if (wpa_parse_wpa_ie_wpa(bss->wpaie, 2 + bss->wpaie[1], &data)
                    < 0) {
-                       wpa_printf(MSG_INFO, "Failed to parse WPA IE from "
-                                  MACSTR, MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "Failed to parse WPA IE from "
+                                MACSTR, MAC2STR(bss->bssid));
                } else {
                        bss->proto |= data.proto;
                        bss->pairwise_cipher |= data.pairwise_cipher;
@@ -232,8 +226,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
        if (bss->rsnie[0]) {
                if (wpa_parse_wpa_ie_rsn(bss->rsnie, 2 + bss->rsnie[1], &data)
                    < 0) {
-                       wpa_printf(MSG_INFO, "Failed to parse RSN IE from "
-                                  MACSTR, MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "Failed to parse RSN IE from "
+                                MACSTR, MAC2STR(bss->bssid));
                } else {
                        bss->proto |= data.proto;
                        bss->pairwise_cipher |= data.pairwise_cipher;
index 5e51310..ee1f1a6 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * CTR with CBC-MAC Protocol (CCMP)
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -17,6 +11,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
 #include "wlantest.h"
 
 
@@ -82,29 +77,13 @@ static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
 }
 
 
-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++;
-}
-
-
 u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                  const u8 *data, size_t data_len, size_t *decrypted_len)
 {
-       u8 aad[2 + 30], nonce[13];
+       u8 aad[30], nonce[13];
        size_t aad_len;
-       u8 b[AES_BLOCK_SIZE], x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
-       void *aes;
-       const u8 *m, *mpos, *mic;
-       size_t mlen, last;
-       int i;
-       u8 *plain, *ppos;
-       u8 t[8];
+       size_t mlen;
+       u8 *plain;
 
        if (data_len < 8 + 8)
                return NULL;
@@ -113,95 +92,15 @@ u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
        if (plain == NULL)
                return NULL;
 
-       aes = aes_encrypt_init(tk, 16);
-       if (aes == NULL) {
-               os_free(plain);
-               return NULL;
-       }
-
-       m = data + 8;
        mlen = data_len - 8 - 8;
-       last = mlen % AES_BLOCK_SIZE;
 
        os_memset(aad, 0, sizeof(aad));
-       ccmp_aad_nonce(hdr, data, &aad[2], &aad_len, nonce);
-       WPA_PUT_BE16(aad, aad_len);
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", &aad[2], aad_len);
+       ccmp_aad_nonce(hdr, data, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
        wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
 
-       /* CCM: M=8 L=2, Adata=1, M' = (M-2)/2 = 3, L' = L-1 = 1 */
-
-       /* A_i = Flags | Nonce N | Counter i */
-       a[0] = 0x01; /* Flags = L' */
-       os_memcpy(&a[1], nonce, 13);
-
-       /* Decryption */
-
-       mic = data + data_len - 8;
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP U", mic, 8);
-       /* U = T XOR S_0; S_0 = E(K, A_0) */
-       WPA_PUT_BE16(&a[14], 0);
-       aes_encrypt(aes, a, x);
-       for (i = 0; i < 8; i++)
-               t[i] = mic[i] ^ x[i];
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP T", t, 8);
-
-       /* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
-       ppos = plain;
-       mpos = m;
-       for (i = 1; i <= mlen / AES_BLOCK_SIZE; i++) {
-               WPA_PUT_BE16(&a[14], i);
-               /* S_i = E(K, A_i) */
-               aes_encrypt(aes, a, ppos);
-               xor_aes_block(ppos, mpos);
-               ppos += AES_BLOCK_SIZE;
-               mpos += AES_BLOCK_SIZE;
-       }
-       if (last) {
-               WPA_PUT_BE16(&a[14], i);
-               aes_encrypt(aes, a, ppos);
-               /* XOR zero-padded last block */
-               for (i = 0; i < last; i++)
-                       *ppos++ ^= *mpos++;
-       }
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP decrypted", plain, mlen);
-
-       /* Authentication */
-       /* B_0: Flags | Nonce N | l(m) */
-       b[0] = 0x40 /* Adata */ | (3 /* M' */ << 3) | 1 /* L' */;
-       os_memcpy(&b[1], nonce, 13);
-       WPA_PUT_BE16(&b[14], mlen);
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_0", b, AES_BLOCK_SIZE);
-       aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_1", aad, AES_BLOCK_SIZE);
-       xor_aes_block(aad, x);
-       aes_encrypt(aes, aad, x); /* X_2 = E(K, X_1 XOR B_1) */
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_2", &aad[AES_BLOCK_SIZE],
-                   AES_BLOCK_SIZE);
-       xor_aes_block(&aad[AES_BLOCK_SIZE], x);
-       aes_encrypt(aes, &aad[AES_BLOCK_SIZE], x); /* X_3 = E(K, X_2 XOR B_2)
-                                                   */
-
-       ppos = plain;
-       for (i = 0; i < mlen / AES_BLOCK_SIZE; i++) {
-               /* X_i+1 = E(K, X_i XOR B_i) */
-               xor_aes_block(x, ppos);
-               ppos += AES_BLOCK_SIZE;
-               aes_encrypt(aes, x, x);
-       }
-       if (last) {
-               /* XOR zero-padded last block */
-               for (i = 0; i < last; i++)
-                       x[i] ^= *ppos++;
-               aes_encrypt(aes, x, x);
-       }
-
-       aes_encrypt_deinit(aes);
-
-       if (os_memcmp(x, t, 8) != 0) {
+       if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
+                      data + 8 + mlen, plain) < 0) {
                u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
                wpa_printf(MSG_INFO, "Invalid CCMP MIC in frame: A1=" MACSTR
                           " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
@@ -209,10 +108,10 @@ u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                           MAC2STR(hdr->addr3),
                           WLAN_GET_SEQ_SEQ(seq_ctrl),
                           WLAN_GET_SEQ_FRAG(seq_ctrl));
-               wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen);
                os_free(plain);
                return NULL;
        }
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP decrypted", plain, mlen);
 
        *decrypted_len = mlen;
        return plain;
@@ -233,19 +132,14 @@ void ccmp_get_pn(u8 *pn, const u8 *data)
 u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
                  u8 *pn, int keyid, size_t *encrypted_len)
 {
-       u8 aad[2 + 30], nonce[13];
-       size_t aad_len;
-       u8 b[AES_BLOCK_SIZE], x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
-       void *aes;
-       u8 *crypt, *pos, *ppos, *mpos;
-       size_t plen, last;
+       u8 aad[30], nonce[13];
+       size_t aad_len, plen;
+       u8 *crypt, *pos;
        struct ieee80211_hdr *hdr;
-       int i;
 
        if (len < hdrlen || hdrlen < 24)
                return NULL;
        plen = len - hdrlen;
-       last = plen % AES_BLOCK_SIZE;
 
        crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE);
        if (crypt == NULL)
@@ -264,92 +158,110 @@ u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
        *pos++ = pn[1]; /* PN4 */
        *pos++ = pn[0]; /* PN5 */
 
-       aes = aes_encrypt_init(tk, 16);
-       if (aes == NULL) {
+       os_memset(aad, 0, sizeof(aad));
+       ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
+
+       if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
+                      pos, pos + plen) < 0) {
                os_free(crypt);
                return NULL;
        }
 
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
+
+       *encrypted_len = hdrlen + 8 + plen + 8;
+
+       return crypt;
+}
+
+
+u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
+                     const u8 *data, size_t data_len, size_t *decrypted_len)
+{
+       u8 aad[30], nonce[13];
+       size_t aad_len;
+       size_t mlen;
+       u8 *plain;
+
+       if (data_len < 8 + 16)
+               return NULL;
+
+       plain = os_malloc(data_len + AES_BLOCK_SIZE);
+       if (plain == NULL)
+               return NULL;
+
+       mlen = data_len - 8 - 16;
+
        os_memset(aad, 0, sizeof(aad));
-       ccmp_aad_nonce(hdr, crypt + hdrlen, &aad[2], &aad_len, nonce);
-       WPA_PUT_BE16(aad, aad_len);
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", &aad[2], aad_len);
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
+       ccmp_aad_nonce(hdr, data, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
 
-       /* Authentication */
-       /* B_0: Flags | Nonce N | l(m) */
-       b[0] = 0x40 /* Adata */ | (3 /* M' */ << 3) | 1 /* L' */;
-       os_memcpy(&b[1], nonce, 13);
-       WPA_PUT_BE16(&b[14], plen);
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_0", b, AES_BLOCK_SIZE);
-       aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_1", aad, AES_BLOCK_SIZE);
-       xor_aes_block(aad, x);
-       aes_encrypt(aes, aad, x); /* X_2 = E(K, X_1 XOR B_1) */
-
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP B_2", &aad[AES_BLOCK_SIZE],
-                   AES_BLOCK_SIZE);
-       xor_aes_block(&aad[AES_BLOCK_SIZE], x);
-       aes_encrypt(aes, &aad[AES_BLOCK_SIZE], x); /* X_3 = E(K, X_2 XOR B_2)
-                                                   */
-
-       ppos = frame + hdrlen;
-       for (i = 0; i < plen / AES_BLOCK_SIZE; i++) {
-               /* X_i+1 = E(K, X_i XOR B_i) */
-               xor_aes_block(x, ppos);
-               ppos += AES_BLOCK_SIZE;
-               aes_encrypt(aes, x, x);
-       }
-       if (last) {
-               /* XOR zero-padded last block */
-               for (i = 0; i < last; i++)
-                       x[i] ^= *ppos++;
-               aes_encrypt(aes, x, x);
+       if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
+                      data + 8 + mlen, plain) < 0) {
+               u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
+               wpa_printf(MSG_INFO, "Invalid CCMP-256 MIC in frame: A1=" MACSTR
+                          " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3),
+                          WLAN_GET_SEQ_SEQ(seq_ctrl),
+                          WLAN_GET_SEQ_FRAG(seq_ctrl));
+               os_free(plain);
+               return NULL;
        }
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 decrypted", plain, mlen);
 
-       /* Encryption */
+       *decrypted_len = mlen;
+       return plain;
+}
 
-       /* CCM: M=8 L=2, Adata=1, M' = (M-2)/2 = 3, L' = L-1 = 1 */
 
-       /* A_i = Flags | Nonce N | Counter i */
-       a[0] = 0x01; /* Flags = L' */
-       os_memcpy(&a[1], nonce, 13);
+u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+                     u8 *qos, u8 *pn, int keyid, size_t *encrypted_len)
+{
+       u8 aad[30], nonce[13];
+       size_t aad_len, plen;
+       u8 *crypt, *pos;
+       struct ieee80211_hdr *hdr;
 
-       ppos = crypt + hdrlen + 8;
+       if (len < hdrlen || hdrlen < 24)
+               return NULL;
+       plen = len - hdrlen;
 
-       /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
-       mpos = frame + hdrlen;
-       for (i = 1; i <= plen / AES_BLOCK_SIZE; i++) {
-               WPA_PUT_BE16(&a[14], i);
-               /* S_i = E(K, A_i) */
-               aes_encrypt(aes, a, ppos);
-               xor_aes_block(ppos, mpos);
-               ppos += AES_BLOCK_SIZE;
-               mpos += AES_BLOCK_SIZE;
-       }
-       if (last) {
-               WPA_PUT_BE16(&a[14], i);
-               aes_encrypt(aes, a, ppos);
-               /* XOR zero-padded last block */
-               for (i = 0; i < last; i++)
-                       *ppos++ ^= *mpos++;
-       }
+       crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
+       if (crypt == NULL)
+               return NULL;
+
+       os_memcpy(crypt, frame, hdrlen);
+       hdr = (struct ieee80211_hdr *) crypt;
+       hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+       pos = crypt + hdrlen;
+       *pos++ = pn[5]; /* PN0 */
+       *pos++ = pn[4]; /* PN1 */
+       *pos++ = 0x00; /* Rsvd */
+       *pos++ = 0x20 | (keyid << 6);
+       *pos++ = pn[3]; /* PN2 */
+       *pos++ = pn[2]; /* PN3 */
+       *pos++ = pn[1]; /* PN4 */
+       *pos++ = pn[0]; /* PN5 */
 
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP T", x, 8);
-       /* U = T XOR S_0; S_0 = E(K, A_0) */
-       WPA_PUT_BE16(&a[14], 0);
-       aes_encrypt(aes, a, b);
-       for (i = 0; i < 8; i++)
-               ppos[i] = x[i] ^ b[i];
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP U", ppos, 8);
+       os_memset(aad, 0, sizeof(aad));
+       ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
 
-       wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
+       if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len,
+                      pos, pos + plen) < 0) {
+               os_free(crypt);
+               return NULL;
+       }
 
-       aes_encrypt_deinit(aes);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 encrypted", crypt + hdrlen + 8,
+                   plen);
 
-       *encrypted_len = hdrlen + 8 + plen + 8;
+       *encrypted_len = hdrlen + 8 + plen + 16;
 
        return crypt;
 }
index c1747d8..adbbda5 100644 (file)
@@ -2,14 +2,8 @@
  * 32-bit CRC for FCS calculation
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index 2132b2b..bed5d6c 100644 (file)
@@ -2,14 +2,8 @@
  * wlantest control interface
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -990,6 +984,15 @@ static void info_print_state(char *buf, size_t len, int state)
 }
 
 
+static void info_print_gtk(char *buf, size_t len, struct wlantest_sta *sta)
+{
+       size_t pos;
+
+       pos = os_snprintf(buf, len, "IDX=%d,GTK=", sta->gtk_idx);
+       wpa_snprintf_hex(buf + pos, len - pos, sta->gtk, sta->gtk_len);
+}
+
+
 static void ctrl_info_sta(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
 {
        u8 *addr;
@@ -1029,6 +1032,9 @@ static void ctrl_info_sta(struct wlantest *wt, int sock, u8 *cmd, size_t clen)
        case WLANTEST_STA_INFO_STATE:
                info_print_state(resp, sizeof(resp), sta->state);
                break;
+       case WLANTEST_STA_INFO_GTK:
+               info_print_gtk(resp, sizeof(resp), sta);
+               break;
        default:
                ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD);
                return;
diff --git a/wlantest/gcmp.c b/wlantest/gcmp.c
new file mode 100644 (file)
index 0000000..d8535d0
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * GCM with GMAC Protocol (GCMP)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
+#include "wlantest.h"
+
+
+static void gcmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
+                          u8 *aad, size_t *aad_len, u8 *nonce)
+{
+       u16 fc, stype, seq;
+       int qos = 0, addr4 = 0;
+       u8 *pos;
+
+       fc = le_to_host16(hdr->frame_control);
+       stype = WLAN_FC_GET_STYPE(fc);
+       if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+           (WLAN_FC_TODS | WLAN_FC_FROMDS))
+               addr4 = 1;
+
+       if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
+               fc &= ~0x0070; /* Mask subtype bits */
+               if (stype & 0x08) {
+                       const u8 *qc;
+                       qos = 1;
+                       fc &= ~WLAN_FC_ORDER;
+                       qc = (const u8 *) (hdr + 1);
+                       if (addr4)
+                               qc += ETH_ALEN;
+               }
+       }
+
+       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
+       fc |= WLAN_FC_ISWEP;
+       WPA_PUT_LE16(aad, fc);
+       pos = aad + 2;
+       os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
+       pos += 3 * ETH_ALEN;
+       seq = le_to_host16(hdr->seq_ctrl);
+       seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
+       WPA_PUT_LE16(pos, seq);
+       pos += 2;
+
+       os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
+       pos += addr4 * ETH_ALEN;
+       if (qos) {
+               pos[0] &= ~0x70;
+               if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
+                       pos[0] &= ~0x80;
+               pos++;
+               *pos++ = 0x00;
+       }
+
+       *aad_len = pos - aad;
+
+       os_memcpy(nonce, hdr->addr2, ETH_ALEN);
+       nonce[6] = data[7]; /* PN5 */
+       nonce[7] = data[6]; /* PN4 */
+       nonce[8] = data[5]; /* PN3 */
+       nonce[9] = data[4]; /* PN2 */
+       nonce[10] = data[1]; /* PN1 */
+       nonce[11] = data[0]; /* PN0 */
+}
+
+
+u8 * gcmp_decrypt(const u8 *tk, size_t tk_len, const struct ieee80211_hdr *hdr,
+                 const u8 *data, size_t data_len, size_t *decrypted_len)
+{
+       u8 aad[30], nonce[12], *plain;
+       size_t aad_len, mlen;
+       const u8 *m;
+
+       if (data_len < 8 + 16)
+               return NULL;
+
+       plain = os_malloc(data_len + AES_BLOCK_SIZE);
+       if (plain == NULL)
+               return NULL;
+
+       m = data + 8;
+       mlen = data_len - 8 - 16;
+
+       os_memset(aad, 0, sizeof(aad));
+       gcmp_aad_nonce(hdr, data, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
+
+       if (aes_gcm_ad(tk, tk_len, nonce, sizeof(nonce), m, mlen, aad, aad_len,
+                      m + mlen, plain) < 0) {
+               u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
+               wpa_printf(MSG_INFO, "Invalid GCMP frame: A1=" MACSTR
+                          " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
+                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                          MAC2STR(hdr->addr3),
+                          WLAN_GET_SEQ_SEQ(seq_ctrl),
+                          WLAN_GET_SEQ_FRAG(seq_ctrl));
+               os_free(plain);
+               return NULL;
+       }
+
+       *decrypted_len = mlen;
+       return plain;
+}
+
+
+u8 * gcmp_encrypt(const u8 *tk, size_t tk_len, u8 *frame, size_t len,
+                 size_t hdrlen, u8 *qos,
+                 u8 *pn, int keyid, size_t *encrypted_len)
+{
+       u8 aad[30], nonce[12], *crypt, *pos;
+       size_t aad_len, plen;
+       struct ieee80211_hdr *hdr;
+
+       if (len < hdrlen || hdrlen < 24)
+               return NULL;
+       plen = len - hdrlen;
+
+       crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
+       if (crypt == NULL)
+               return NULL;
+
+       os_memcpy(crypt, frame, hdrlen);
+       hdr = (struct ieee80211_hdr *) crypt;
+       hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+       pos = crypt + hdrlen;
+       *pos++ = pn[5]; /* PN0 */
+       *pos++ = pn[4]; /* PN1 */
+       *pos++ = 0x00; /* Rsvd */
+       *pos++ = 0x20 | (keyid << 6);
+       *pos++ = pn[3]; /* PN2 */
+       *pos++ = pn[2]; /* PN3 */
+       *pos++ = pn[1]; /* PN4 */
+       *pos++ = pn[0]; /* PN5 */
+
+       os_memset(aad, 0, sizeof(aad));
+       gcmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP nonce", nonce, sizeof(nonce));
+
+       if (aes_gcm_ae(tk, tk_len, nonce, sizeof(nonce), frame + hdrlen, plen,
+                      aad, aad_len, pos, pos + plen) < 0) {
+               os_free(crypt);
+               return NULL;
+       }
+
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP MIC", pos + plen, 16);
+       wpa_hexdump(MSG_EXCESSIVE, "GCMP encrypted", pos, plen);
+
+       *encrypted_len = hdrlen + 8 + plen + 16;
+
+       return crypt;
+}
index e8e7de7..5b14ca7 100644 (file)
@@ -2,14 +2,8 @@
  * wlantest frame injection
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -87,58 +81,23 @@ static int is_robust_mgmt(u8 *frame, size_t len)
 static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss,
                               u8 *frame, size_t len, int incorrect_key)
 {
-       u8 *prot, *pos, *buf;
-       u8 mic[16];
+       u8 *prot;
        u8 dummy[16];
        int ret;
-       u16 fc;
-       struct ieee80211_hdr *hdr;
        size_t plen;
 
        if (!bss->igtk_set[bss->igtk_idx])
                return -1;
 
-       plen = len + 18;
-       prot = os_malloc(plen);
-       if (prot == NULL)
-               return -1;
-       os_memcpy(prot, frame, len);
-       pos = prot + len;
-       *pos++ = WLAN_EID_MMIE;
-       *pos++ = 16;
-       WPA_PUT_LE16(pos, bss->igtk_idx);
-       pos += 2;
+       os_memset(dummy, 0x11, sizeof(dummy));
        inc_byte_array(bss->ipn[bss->igtk_idx], 6);
-       os_memcpy(pos, bss->ipn[bss->igtk_idx], 6);
-       pos += 6;
-       os_memset(pos, 0, 8); /* MIC */
 
-       buf = os_malloc(plen + 20 - 24);
-       if (buf == NULL) {
-               os_free(prot);
-               return -1;
-       }
-
-       /* BIP AAD: FC(masked) A1 A2 A3 */
-       hdr = (struct ieee80211_hdr *) frame;
-       fc = le_to_host16(hdr->frame_control);
-       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
-       WPA_PUT_LE16(buf, fc);
-       os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
-       os_memcpy(buf + 20, prot + 24, plen - 24);
-       wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
-       /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
-       os_memset(dummy, 0x11, sizeof(dummy));
-       if (omac1_aes_128(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
-                         buf, plen + 20 - 24, mic) < 0) {
-               os_free(prot);
-               os_free(buf);
+       prot = bip_protect(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
+                          frame, len, bss->ipn[bss->igtk_idx],
+                          bss->igtk_idx, &plen);
+       if (prot == NULL)
                return -1;
-       }
-       os_free(buf);
 
-       os_memcpy(pos, mic, 8);
-       wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
 
        ret = inject_frame(wt->monitor_sock, prot, plen);
        os_free(prot);
@@ -326,9 +285,8 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
                return -1;
        }
 
-       if (prot != WLANTEST_INJECT_UNPROTECTED &&
-           (bss == NULL || sta == NULL)) {
-               wpa_printf(MSG_INFO, "No BSS/STA information to inject "
+       if (prot != WLANTEST_INJECT_UNPROTECTED && bss == NULL) {
+               wpa_printf(MSG_INFO, "No BSS information to inject "
                           "protected frames");
                return -1;
        }
index c16893a..afcc380 100644 (file)
@@ -2,14 +2,8 @@
  * Linux packet socket monitor
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -33,8 +27,12 @@ static void monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
+       clear_notes(wt);
+       os_free(wt->decrypted);
+       wt->decrypted = NULL;
        write_pcap_captured(wt, buf, len);
        wlantest_process(wt, buf, len);
+       write_pcapng_captured(wt, buf, len);
 }
 
 
index a4dd87d..5e75445 100644 (file)
@@ -2,14 +2,8 @@
  * Received frame processing
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -106,12 +100,12 @@ static void rx_update_ps(struct wlantest *wt, const struct ieee80211_hdr *hdr,
        if (!to_ap) {
                if (sta->pwrmgt && !sta->pspoll) {
                        u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
-                       wpa_printf(MSG_DEBUG, "AP " MACSTR " sent a frame "
-                                  "(%u:%u) to a sleeping STA " MACSTR
-                                  " (seq=%u)",
-                                  MAC2STR(sta->bss->bssid),
-                                  type, stype, MAC2STR(sta->addr),
-                                  WLAN_GET_SEQ_SEQ(seq_ctrl));
+                       add_note(wt, MSG_DEBUG, "AP " MACSTR " sent a frame "
+                                "(%u:%u) to a sleeping STA " MACSTR
+                                " (seq=%u)",
+                                MAC2STR(sta->bss->bssid),
+                                type, stype, MAC2STR(sta->addr),
+                                WLAN_GET_SEQ_SEQ(seq_ctrl));
                } else
                        sta->pspoll = 0;
                return;
@@ -128,12 +122,12 @@ static void rx_update_ps(struct wlantest *wt, const struct ieee80211_hdr *hdr,
                 * maintain state through the frame exchange.
                 */
                if (sta->pwrmgt && !(fc & WLAN_FC_PWRMGT)) {
-                       wpa_printf(MSG_DEBUG, "STA " MACSTR " woke up from "
-                                  "sleep", MAC2STR(sta->addr));
+                       add_note(wt, MSG_DEBUG, "STA " MACSTR " woke up from "
+                                "sleep", MAC2STR(sta->addr));
                        sta->pwrmgt = 0;
                } else if (!sta->pwrmgt && (fc & WLAN_FC_PWRMGT)) {
-                       wpa_printf(MSG_DEBUG, "STA " MACSTR " went to sleep",
-                                  MAC2STR(sta->addr));
+                       add_note(wt, MSG_DEBUG, "STA " MACSTR " went to sleep",
+                                MAC2STR(sta->addr));
                        sta->pwrmgt = 1;
                }
        }
@@ -167,10 +161,10 @@ static int rx_duplicate(struct wlantest *wt, const struct ieee80211_hdr *hdr,
 
        if ((fc & WLAN_FC_RETRY) && hdr->seq_ctrl == *seq_ctrl) {
                u16 s = le_to_host16(hdr->seq_ctrl);
-               wpa_printf(MSG_MSGDUMP, "Ignore duplicated frame (seq=%u "
-                          "frag=%u A1=" MACSTR " A2=" MACSTR ")",
-                          WLAN_GET_SEQ_SEQ(s), WLAN_GET_SEQ_FRAG(s),
-                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2));
+               add_note(wt, MSG_MSGDUMP, "Ignore duplicated frame (seq=%u "
+                        "frag=%u A1=" MACSTR " A2=" MACSTR ")",
+                        WLAN_GET_SEQ_SEQ(s), WLAN_GET_SEQ_FRAG(s),
+                        MAC2STR(hdr->addr1), MAC2STR(hdr->addr2));
                return 1;
        }
 
@@ -187,8 +181,8 @@ static void rx_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr)
 
        if (wt->last_len < 24 || (last->addr1[0] & 0x01) ||
            os_memcmp(hdr->addr1, last->addr2, ETH_ALEN) != 0) {
-               wpa_printf(MSG_MSGDUMP, "Unknown Ack frame (previous frame "
-                          "not seen)");
+               add_note(wt, MSG_MSGDUMP, "Unknown Ack frame (previous frame "
+                        "not seen)");
                return;
        }
 
@@ -283,7 +277,7 @@ void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
        wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
 
        if (ieee80211_radiotap_iterator_init(&iter, (void *) data, len)) {
-               wpa_printf(MSG_INFO, "Invalid radiotap frame");
+               add_note(wt, MSG_INFO, "Invalid radiotap frame");
                return;
        }
 
@@ -294,8 +288,8 @@ void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
                if (ret == -ENOENT)
                        break;
                if (ret) {
-                       wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
-                                  ret);
+                       add_note(wt, MSG_INFO, "Invalid radiotap header: %d",
+                                ret);
                        return;
                }
                switch (iter.this_arg_index) {
@@ -316,7 +310,7 @@ void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
        }
 
        if (iter.max_length == 8) {
-               wpa_printf(MSG_DEBUG, "Skip frame inserted by wlantest");
+               add_note(wt, MSG_DEBUG, "Skip frame inserted by wlantest");
                return;
        }
        frame = data + iter.max_length;
@@ -326,8 +320,8 @@ void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
                frame_len -= 4;
                fcspos = frame + frame_len;
                if (check_fcs(frame, frame_len, fcspos) < 0) {
-                       wpa_printf(MSG_EXCESSIVE, "Drop RX frame with invalid "
-                                  "FCS");
+                       add_note(wt, MSG_EXCESSIVE, "Drop RX frame with "
+                                "invalid FCS");
                        wt->fcs_error++;
                        return;
                }
@@ -337,8 +331,13 @@ void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
                return;
        if (!txflags)
                rx_frame(wt, frame, frame_len);
-       else
+       else {
+               add_note(wt, MSG_EXCESSIVE, "TX status - process as RX of "
+                        "local frame");
                tx_status(wt, frame, frame_len, !failed);
+               /* Process as RX frame to support local monitor interface */
+               rx_frame(wt, frame, frame_len);
+       }
 }
 
 
@@ -369,8 +368,8 @@ void wlantest_process_prism(struct wlantest *wt, const u8 *data, size_t len)
                frame_len -= 4;
                fcspos = frame + frame_len;
                if (check_fcs(frame, frame_len, fcspos) < 0) {
-                       wpa_printf(MSG_EXCESSIVE, "Drop RX frame with invalid "
-                                  "FCS");
+                       add_note(wt, MSG_EXCESSIVE, "Drop RX frame with "
+                                "invalid FCS");
                        wt->fcs_error++;
                        return;
                }
@@ -383,5 +382,19 @@ void wlantest_process_prism(struct wlantest *wt, const u8 *data, size_t len)
 void wlantest_process_80211(struct wlantest *wt, const u8 *data, size_t len)
 {
        wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
+
+       if (wt->assume_fcs && len >= 4) {
+               const u8 *fcspos;
+
+               len -= 4;
+               fcspos = data + len;
+               if (check_fcs(data, len, fcspos) < 0) {
+                       add_note(wt, MSG_EXCESSIVE, "Drop RX frame with "
+                                "invalid FCS");
+                       wt->fcs_error++;
+                       return;
+               }
+       }
+
        rx_frame(wt, data, len);
 }
index fd8b1e8..7c3ce18 100644 (file)
@@ -2,14 +2,8 @@
  * PCAP capture file reader
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #include "wlantest.h"
 
 
+static void write_pcap_with_radiotap(struct wlantest *wt,
+                                    const u8 *data, size_t data_len)
+{
+       struct pcap_pkthdr h;
+       u8 rtap[] = {
+               0x00 /* rev */,
+               0x00 /* pad */,
+               0x0a, 0x00, /* header len */
+               0x02, 0x00, 0x00, 0x00, /* present flags */
+               0x00, /* flags */
+               0x00 /* pad */
+       };
+       u8 *buf;
+       size_t len;
+
+       if (wt->assume_fcs)
+               rtap[8] |= 0x10;
+
+       os_memset(&h, 0, sizeof(h));
+       h.ts = wt->write_pcap_time;
+       len = sizeof(rtap) + data_len;
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return;
+       os_memcpy(buf, rtap, sizeof(rtap));
+       os_memcpy(buf + sizeof(rtap), data, data_len);
+       h.caplen = len;
+       h.len = len;
+       pcap_dump(wt->write_pcap_dumper, &h, buf);
+       os_free(buf);
+}
+
+
 int read_cap_file(struct wlantest *wt, const char *fname)
 {
        char errbuf[PCAP_ERRBUF_SIZE];
@@ -46,6 +73,10 @@ int read_cap_file(struct wlantest *wt, const char *fname)
        wpa_printf(MSG_DEBUG, "pcap datalink type: %d", dlt);
 
        for (;;) {
+               clear_notes(wt);
+               os_free(wt->decrypted);
+               wt->decrypted = NULL;
+
                res = pcap_next_ex(pcap, &hdr, &data);
                if (res == -2)
                        break; /* No more packets */
@@ -67,12 +98,16 @@ int read_cap_file(struct wlantest *wt, const char *fname)
                           hdr->caplen, hdr->len);
                if (wt->write_pcap_dumper) {
                        wt->write_pcap_time = hdr->ts;
-                       pcap_dump(wt->write_pcap_dumper, hdr, data);
+                       if (dlt == DLT_IEEE802_11)
+                               write_pcap_with_radiotap(wt, data, hdr->caplen);
+                       else
+                               pcap_dump(wt->write_pcap_dumper, hdr, data);
                }
                if (hdr->caplen < hdr->len) {
-                       wpa_printf(MSG_DEBUG, "pcap: Dropped incomplete frame "
-                                  "(%u/%u captured)",
-                                  hdr->caplen, hdr->len);
+                       add_note(wt, MSG_DEBUG, "pcap: Dropped incomplete "
+                                "frame (%u/%u captured)",
+                                hdr->caplen, hdr->len);
+                       write_pcapng_write_read(wt, dlt, hdr, data);
                        continue;
                }
                count++;
@@ -85,7 +120,9 @@ int read_cap_file(struct wlantest *wt, const char *fname)
                        break;
                case DLT_IEEE802_11:
                        wlantest_process_80211(wt, data, hdr->caplen);
+                       break;
                }
+               write_pcapng_write_read(wt, dlt, hdr, data);
        }
 
        pcap_close(pcap);
index b7f1a89..9d439be 100644 (file)
@@ -2,14 +2,8 @@
  * Received Data frame processing
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -114,45 +108,45 @@ static void rx_data_bss_prot_group(struct wlantest *wt,
        if (bss == NULL)
                return;
        if (len < 4) {
-               wpa_printf(MSG_INFO, "Too short group addressed data frame");
+               add_note(wt, MSG_INFO, "Too short group addressed data frame");
                return;
        }
 
        if (bss->group_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
            !(data[3] & 0x20)) {
-                   wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from "
-                              MACSTR " did not have ExtIV bit set to 1",
-                              MAC2STR(bss->bssid));
-                   return;
+               add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from "
+                        MACSTR " did not have ExtIV bit set to 1",
+                        MAC2STR(bss->bssid));
+               return;
        }
 
        if (bss->group_cipher == WPA_CIPHER_TKIP) {
                if (data[3] & 0x1f) {
-                       wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
-                                  "non-zero reserved bit",
-                                  MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
+                                " used non-zero reserved bit",
+                                MAC2STR(bss->bssid));
                }
                if (data[1] != ((data[0] | 0x20) & 0x7f)) {
-                       wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
-                                  "incorrect WEPSeed[1] (was 0x%x, expected "
-                                  "0x%x)",
-                                  MAC2STR(bss->bssid), data[1],
-                                  (data[0] | 0x20) & 0x7f);
+                       add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
+                                " used incorrect WEPSeed[1] (was 0x%x, "
+                                "expected 0x%x)",
+                                MAC2STR(bss->bssid), data[1],
+                                (data[0] | 0x20) & 0x7f);
                }
        } else if (bss->group_cipher == WPA_CIPHER_CCMP) {
                if (data[2] != 0 || (data[3] & 0x1f) != 0) {
-                       wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used "
-                                  "non-zero reserved bit",
-                                  MAC2STR(bss->bssid));
+                       add_note(wt, MSG_INFO, "CCMP frame from " MACSTR
+                                " used non-zero reserved bit",
+                                MAC2STR(bss->bssid));
                }
        }
 
        keyid = data[3] >> 6;
        if (bss->gtk_len[keyid] == 0 && bss->group_cipher != WPA_CIPHER_WEP40)
        {
-               wpa_printf(MSG_MSGDUMP, "No GTK known to decrypt the frame "
-                          "(A2=" MACSTR " KeyID=%d)",
-                          MAC2STR(hdr->addr2), keyid);
+               add_note(wt, MSG_MSGDUMP, "No GTK known to decrypt the frame "
+                        "(A2=" MACSTR " KeyID=%d)",
+                        MAC2STR(hdr->addr2), keyid);
                return;
        }
 
@@ -164,12 +158,12 @@ static void rx_data_bss_prot_group(struct wlantest *wt,
                ccmp_get_pn(pn, data);
        if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) {
                u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
-               wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
-                          " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
-                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
-                          MAC2STR(hdr->addr3),
-                          WLAN_GET_SEQ_SEQ(seq_ctrl),
-                          WLAN_GET_SEQ_FRAG(seq_ctrl));
+               add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
+                        " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
+                        MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                        MAC2STR(hdr->addr3),
+                        WLAN_GET_SEQ_SEQ(seq_ctrl),
+                        WLAN_GET_SEQ_FRAG(seq_ctrl));
                wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
                wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6);
        }
@@ -189,7 +183,8 @@ skip_replay_det:
                os_memcpy(bss->rsc[keyid], pn, 6);
                write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
                                     decrypted, dlen);
-       }
+       } else
+               add_note(wt, MSG_DEBUG, "Failed to decrypt frame");
        os_free(decrypted);
 }
 
@@ -207,7 +202,7 @@ static void rx_data_bss_prot(struct wlantest *wt,
        size_t dlen;
        int tid;
        u8 pn[6], *rsc;
-       struct wlantest_tdls *tdls = NULL;
+       struct wlantest_tdls *tdls = NULL, *found;
        const u8 *tk = NULL;
 
        if (hdr->addr1[0] & 0x01) {
@@ -235,64 +230,71 @@ static void rx_data_bss_prot(struct wlantest *wt,
                sta2 = sta_find(bss, hdr->addr1);
                if (sta == NULL || sta2 == NULL)
                        return;
+               found = NULL;
                dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list)
                {
                        if ((tdls->init == sta && tdls->resp == sta2) ||
                            (tdls->init == sta2 && tdls->resp == sta)) {
-                               if (!tdls->link_up)
-                                       wpa_printf(MSG_DEBUG, "TDLS: Link not "
-                                                  "up, but Data frame seen");
-                               tk = tdls->tpk.tk;
-                               break;
+                               found = tdls;
+                               if (tdls->link_up)
+                                       break;
                        }
                }
+               if (found) {
+                       if (!found->link_up)
+                               add_note(wt, MSG_DEBUG,
+                                        "TDLS: Link not up, but Data "
+                                        "frame seen");
+                       tk = found->tpk.tk;
+                       tdls = found;
+               }
        }
        if ((sta == NULL ||
             (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) &&
            tk == NULL) {
-               wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame");
+               add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
                return;
        }
 
        if (len < 4) {
-               wpa_printf(MSG_INFO, "Too short encrypted data frame");
+               add_note(wt, MSG_INFO, "Too short encrypted data frame");
                return;
        }
 
        if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
            !(data[3] & 0x20)) {
-                   wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from "
-                              MACSTR " did not have ExtIV bit set to 1",
-                              MAC2STR(src));
-                   return;
+               add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from "
+                        MACSTR " did not have ExtIV bit set to 1",
+                        MAC2STR(src));
+               return;
        }
 
        if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) {
                if (data[3] & 0x1f) {
-                       wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
-                                  "non-zero reserved bit",
-                                  MAC2STR(hdr->addr2));
+                       add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
+                                " used non-zero reserved bit",
+                                MAC2STR(hdr->addr2));
                }
                if (data[1] != ((data[0] | 0x20) & 0x7f)) {
-                       wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
-                                  "incorrect WEPSeed[1] (was 0x%x, expected "
-                                  "0x%x)",
-                                  MAC2STR(hdr->addr2), data[1],
-                                  (data[0] | 0x20) & 0x7f);
+                       add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
+                                " used incorrect WEPSeed[1] (was 0x%x, "
+                                "expected 0x%x)",
+                                MAC2STR(hdr->addr2), data[1],
+                                (data[0] | 0x20) & 0x7f);
                }
        } else if (tk || sta->pairwise_cipher == WPA_CIPHER_CCMP) {
                if (data[2] != 0 || (data[3] & 0x1f) != 0) {
-                       wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used "
-                                  "non-zero reserved bit",
-                                  MAC2STR(hdr->addr2));
+                       add_note(wt, MSG_INFO, "CCMP frame from " MACSTR
+                                " used non-zero reserved bit",
+                                MAC2STR(hdr->addr2));
                }
        }
 
        keyid = data[3] >> 6;
        if (keyid != 0) {
-               wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in "
-                          "individually addressed Data frame from " MACSTR,
-                          keyid, MAC2STR(hdr->addr2));
+               add_note(wt, MSG_INFO, "Unexpected non-zero KeyID %d in "
+                        "individually addressed Data frame from " MACSTR,
+                        keyid, MAC2STR(hdr->addr2));
        }
 
        if (qos)
@@ -318,12 +320,12 @@ static void rx_data_bss_prot(struct wlantest *wt,
                ccmp_get_pn(pn, data);
        if (os_memcmp(pn, rsc, 6) <= 0) {
                u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
-               wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
-                          " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
-                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
-                          MAC2STR(hdr->addr3),
-                          WLAN_GET_SEQ_SEQ(seq_ctrl),
-                          WLAN_GET_SEQ_FRAG(seq_ctrl));
+               add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
+                        " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
+                        MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                        MAC2STR(hdr->addr3),
+                        WLAN_GET_SEQ_SEQ(seq_ctrl),
+                        WLAN_GET_SEQ_FRAG(seq_ctrl));
                wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
                wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
        }
@@ -347,7 +349,8 @@ skip_replay_det:
                                dlen, 1, peer_addr);
                write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
                                     decrypted, dlen);
-       }
+       } else
+               add_note(wt, MSG_DEBUG, "Failed to decrypt frame");
        os_free(decrypted);
 }
 
@@ -405,7 +408,7 @@ static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *bssid,
 {
        struct wlantest_bss *bss;
        struct wlantest_sta *sta1, *sta2;
-       struct wlantest_tdls *tdls;
+       struct wlantest_tdls *tdls, *found = NULL;
 
        bss = bss_find(wt, bssid);
        if (bss == NULL)
@@ -419,11 +422,14 @@ static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *bssid,
 
        dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
                if ((tdls->init == sta1 && tdls->resp == sta2) ||
-                   (tdls->init == sta2 && tdls->resp == sta1))
-                       return tdls;
+                   (tdls->init == sta2 && tdls->resp == sta1)) {
+                       found = tdls;
+                       if (tdls->link_up)
+                               break;
+               }
        }
 
-       return NULL;
+       return found;
 }
 
 
index 5a87326..b18b3cf 100644 (file)
@@ -2,14 +2,8 @@
  * Received Data frame processing for EAPOL messages
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -19,6 +13,7 @@
 #include "crypto/crypto.h"
 #include "common/defs.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/eapol_common.h"
 #include "common/wpa_common.h"
 #include "rsn_supp/wpa_ie.h"
@@ -84,19 +79,20 @@ static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
        eapol = (const struct ieee802_1x_hdr *) data;
        hdr = (const struct wpa_eapol_key *) (eapol + 1);
        if (is_zero(hdr->key_nonce, WPA_NONCE_LEN)) {
-               wpa_printf(MSG_INFO, "EAPOL-Key 1/4 from " MACSTR " used "
-                          "zero nonce", MAC2STR(src));
+               add_note(wt, MSG_INFO, "EAPOL-Key 1/4 from " MACSTR
+                        " used zero nonce", MAC2STR(src));
        }
        if (!is_zero(hdr->key_rsc, 8)) {
-               wpa_printf(MSG_INFO, "EAPOL-Key 1/4 from " MACSTR " used "
-                          "non-zero Key RSC", MAC2STR(src));
+               add_note(wt, MSG_INFO, "EAPOL-Key 1/4 from " MACSTR
+                        " used non-zero Key RSC", MAC2STR(src));
        }
        os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN);
 }
 
 
-static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta,
-                  u16 ver, const u8 *data, size_t len,
+static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
+                  struct wlantest_sta *sta, u16 ver,
+                  const u8 *data, size_t len,
                   struct wlantest_pmk *pmk)
 {
        struct wpa_ptk ptk;
@@ -117,6 +113,7 @@ static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta,
                 * Rekeying - use new PTK for EAPOL-Key frames, but continue
                 * using the old PTK for frame decryption.
                 */
+               add_note(wt, MSG_DEBUG, "Derived PTK during rekeying");
                os_memcpy(&sta->tptk, &ptk, sizeof(ptk));
                wpa_hexdump(MSG_DEBUG, "TPTK:KCK", sta->tptk.kck, 16);
                wpa_hexdump(MSG_DEBUG, "TPTK:KEK", sta->tptk.kek, 16);
@@ -127,6 +124,7 @@ static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta,
                sta->tptk_set = 1;
                return 0;
        }
+       add_note(wt, MSG_DEBUG, "Derived new PTK");
        os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
        wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
        wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
@@ -150,16 +148,16 @@ static void derive_ptk(struct wlantest *wt, struct wlantest_bss *bss,
                   MAC2STR(sta->addr));
        dl_list_for_each(pmk, &bss->pmk, struct wlantest_pmk, list) {
                wpa_printf(MSG_DEBUG, "Try per-BSS PMK");
-               if (try_pmk(bss, sta, ver, data, len, pmk) == 0)
+               if (try_pmk(wt, bss, sta, ver, data, len, pmk) == 0)
                        return;
        }
 
        dl_list_for_each(pmk, &wt->pmk, struct wlantest_pmk, list) {
                wpa_printf(MSG_DEBUG, "Try global PMK");
-               if (try_pmk(bss, sta, ver, data, len, pmk) == 0)
+               if (try_pmk(wt, bss, sta, ver, data, len, pmk) == 0)
                        return;
        }
-       wpa_printf(MSG_DEBUG, "No matching PMK found to derive PTK");
+       add_note(wt, MSG_DEBUG, "No matching PMK found to derive PTK");
 }
 
 
@@ -186,12 +184,12 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
        eapol = (const struct ieee802_1x_hdr *) data;
        hdr = (const struct wpa_eapol_key *) (eapol + 1);
        if (is_zero(hdr->key_nonce, WPA_NONCE_LEN)) {
-               wpa_printf(MSG_INFO, "EAPOL-Key 2/4 from " MACSTR " used "
-                          "zero nonce", MAC2STR(src));
+               add_note(wt, MSG_INFO, "EAPOL-Key 2/4 from " MACSTR
+                        " used zero nonce", MAC2STR(src));
        }
        if (!is_zero(hdr->key_rsc, 8)) {
-               wpa_printf(MSG_INFO, "EAPOL-Key 2/4 from " MACSTR " used "
-                          "non-zero Key RSC", MAC2STR(src));
+               add_note(wt, MSG_INFO, "EAPOL-Key 2/4 from " MACSTR
+                        " used non-zero Key RSC", MAC2STR(src));
        }
        os_memcpy(sta->snonce, hdr->key_nonce, WPA_NONCE_LEN);
        key_info = WPA_GET_BE16(hdr->key_info);
@@ -199,25 +197,27 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
        derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
 
        if (!sta->ptk_set && !sta->tptk_set) {
-               wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/4");
+               add_note(wt, MSG_DEBUG,
+                        "No PTK known to process EAPOL-Key 2/4");
                return;
        }
 
        kck = sta->ptk.kck;
        if (sta->tptk_set) {
-               wpa_printf(MSG_DEBUG, "Use TPTK for validation EAPOL-Key MIC");
+               add_note(wt, MSG_DEBUG,
+                        "Use TPTK for validation EAPOL-Key MIC");
                kck = sta->tptk.kck;
        }
        if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
-               wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
+               add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
                return;
        }
-       wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/4");
+       add_note(wt, MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/4");
 
        key_data = (const u8 *) (hdr + 1);
 
        if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) {
-               wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data");
+               add_note(wt, MSG_INFO, "Failed to parse EAPOL-Key Key Data");
                return;
        }
 
@@ -225,15 +225,28 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
                wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE",
                            ie.wpa_ie, ie.wpa_ie_len);
                if (os_memcmp(ie.wpa_ie, sta->rsnie, ie.wpa_ie_len) != 0) {
-                       wpa_printf(MSG_INFO, "Mismatch in WPA IE between "
-                                  "EAPOL-Key 2/4 and (Re)Association "
-                                  "Request from " MACSTR, MAC2STR(sta->addr));
+                       struct ieee802_11_elems elems;
+                       add_note(wt, MSG_INFO,
+                                "Mismatch in WPA IE between EAPOL-Key 2/4 "
+                                "and (Re)Association Request from " MACSTR,
+                                MAC2STR(sta->addr));
                        wpa_hexdump(MSG_INFO, "WPA IE in EAPOL-Key",
                                    ie.wpa_ie, ie.wpa_ie_len);
                        wpa_hexdump(MSG_INFO, "WPA IE in (Re)Association "
                                    "Request",
                                    sta->rsnie,
                                    sta->rsnie[0] ? 2 + sta->rsnie[1] : 0);
+                       /*
+                        * The sniffer may have missed (Re)Association
+                        * Request, so try to survive with the information from
+                        * EAPOL-Key.
+                        */
+                       os_memset(&elems, 0, sizeof(elems));
+                       elems.wpa_ie = ie.wpa_ie + 2;
+                       elems.wpa_ie_len = ie.wpa_ie_len - 2;
+                       wpa_printf(MSG_DEBUG, "Update STA data based on WPA "
+                                  "IE in EAPOL-Key 2/4");
+                       sta_update_assoc(sta, &elems);
                }
        }
 
@@ -241,21 +254,34 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
                wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE",
                            ie.rsn_ie, ie.rsn_ie_len);
                if (os_memcmp(ie.rsn_ie, sta->rsnie, ie.rsn_ie_len) != 0) {
-                       wpa_printf(MSG_INFO, "Mismatch in RSN IE between "
-                                  "EAPOL-Key 2/4 and (Re)Association "
-                                  "Request from " MACSTR, MAC2STR(sta->addr));
+                       struct ieee802_11_elems elems;
+                       add_note(wt, MSG_INFO,
+                                "Mismatch in RSN IE between EAPOL-Key 2/4 "
+                                "and (Re)Association Request from " MACSTR,
+                                MAC2STR(sta->addr));
                        wpa_hexdump(MSG_INFO, "RSN IE in EAPOL-Key",
                                    ie.rsn_ie, ie.rsn_ie_len);
                        wpa_hexdump(MSG_INFO, "RSN IE in (Re)Association "
                                    "Request",
                                    sta->rsnie,
                                    sta->rsnie[0] ? 2 + sta->rsnie[1] : 0);
+                       /*
+                        * The sniffer may have missed (Re)Association
+                        * Request, so try to survive with the information from
+                        * EAPOL-Key.
+                        */
+                       os_memset(&elems, 0, sizeof(elems));
+                       elems.rsn_ie = ie.rsn_ie + 2;
+                       elems.rsn_ie_len = ie.rsn_ie_len - 2;
+                       wpa_printf(MSG_DEBUG, "Update STA data based on RSN "
+                                  "IE in EAPOL-Key 2/4");
+                       sta_update_assoc(sta, &elems);
                }
        }
 }
 
 
-static u8 * decrypt_eapol_key_data_rc4(const u8 *kek,
+static u8 * decrypt_eapol_key_data_rc4(struct wlantest *wt, const u8 *kek,
                                       const struct wpa_eapol_key *hdr,
                                       size_t *len)
 {
@@ -270,7 +296,7 @@ static u8 * decrypt_eapol_key_data_rc4(const u8 *kek,
        os_memcpy(ek + 16, kek, 16);
        os_memcpy(buf, hdr + 1, keydatalen);
        if (rc4_skip(ek, 32, 256, buf, keydatalen)) {
-               wpa_printf(MSG_INFO, "RC4 failed");
+               add_note(wt, MSG_INFO, "RC4 failed");
                os_free(buf);
                return NULL;
        }
@@ -280,7 +306,7 @@ static u8 * decrypt_eapol_key_data_rc4(const u8 *kek,
 }
 
 
-static u8 * decrypt_eapol_key_data_aes(const u8 *kek,
+static u8 * decrypt_eapol_key_data_aes(struct wlantest *wt, const u8 *kek,
                                       const struct wpa_eapol_key *hdr,
                                       size_t *len)
 {
@@ -288,8 +314,8 @@ static u8 * decrypt_eapol_key_data_aes(const u8 *kek,
        u16 keydatalen = WPA_GET_BE16(hdr->key_data_length);
 
        if (keydatalen % 8) {
-               wpa_printf(MSG_INFO, "Unsupported AES-WRAP len %d",
-                          keydatalen);
+               add_note(wt, MSG_INFO, "Unsupported AES-WRAP len %d",
+                        keydatalen);
                return NULL;
        }
        keydatalen -= 8; /* AES-WRAP adds 8 bytes */
@@ -298,8 +324,9 @@ static u8 * decrypt_eapol_key_data_aes(const u8 *kek,
                return NULL;
        if (aes_unwrap(kek, keydatalen / 8, (u8 *) (hdr + 1), buf)) {
                os_free(buf);
-               wpa_printf(MSG_INFO, "AES unwrap failed - "
-                          "could not decrypt EAPOL-Key key data");
+               add_note(wt, MSG_INFO,
+                        "AES unwrap failed - could not decrypt EAPOL-Key "
+                        "key data");
                return NULL;
        }
 
@@ -308,31 +335,33 @@ static u8 * decrypt_eapol_key_data_aes(const u8 *kek,
 }
 
 
-static u8 * decrypt_eapol_key_data(const u8 *kek, u16 ver,
+static u8 * decrypt_eapol_key_data(struct wlantest *wt, const u8 *kek, u16 ver,
                                   const struct wpa_eapol_key *hdr,
                                   size_t *len)
 {
        switch (ver) {
        case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
-               return decrypt_eapol_key_data_rc4(kek, hdr, len);
+               return decrypt_eapol_key_data_rc4(wt, kek, hdr, len);
        case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
        case WPA_KEY_INFO_TYPE_AES_128_CMAC:
-               return decrypt_eapol_key_data_aes(kek, hdr, len);
+               return decrypt_eapol_key_data_aes(wt, kek, hdr, len);
        default:
-               wpa_printf(MSG_INFO, "Unsupported EAPOL-Key Key Descriptor "
-                          "Version %u", ver);
+               add_note(wt, MSG_INFO,
+                        "Unsupported EAPOL-Key Key Descriptor Version %u",
+                        ver);
                return NULL;
        }
 }
 
 
-static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len,
-                          const u8 *rsc)
+static void learn_kde_keys(struct wlantest *wt, struct wlantest_bss *bss,
+                          struct wlantest_sta *sta,
+                          const u8 *buf, size_t len, const u8 *rsc)
 {
        struct wpa_eapol_ie_parse ie;
 
        if (wpa_supplicant_parse_ies(buf, len, &ie) < 0) {
-               wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data");
+               add_note(wt, MSG_INFO, "Failed to parse EAPOL-Key Key Data");
                return;
        }
 
@@ -354,14 +383,17 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len,
                        id = ie.gtk[0] & 0x03;
                        wpa_printf(MSG_DEBUG, "GTK KeyID=%u tx=%u",
                                   id, !!(ie.gtk[0] & 0x04));
-                       if ((ie.gtk[0] & 0xf8) || ie.gtk[1])
-                               wpa_printf(MSG_INFO, "GTK KDE: Reserved field "
-                                          "set: %02x %02x",
-                                          ie.gtk[0], ie.gtk[1]);
+                       if ((ie.gtk[0] & 0xf8) || ie.gtk[1]) {
+                               add_note(wt, MSG_INFO,
+                                        "GTK KDE: Reserved field set: "
+                                        "%02x %02x", ie.gtk[0], ie.gtk[1]);
+                       }
                        wpa_hexdump(MSG_DEBUG, "GTK", ie.gtk + 2,
                                    ie.gtk_len - 2);
                        bss->gtk_len[id] = ie.gtk_len - 2;
+                       sta->gtk_len = ie.gtk_len - 2;
                        os_memcpy(bss->gtk[id], ie.gtk + 2, ie.gtk_len - 2);
+                       os_memcpy(sta->gtk, ie.gtk + 2, ie.gtk_len - 2);
                        bss->rsc[id][0] = rsc[5];
                        bss->rsc[id][1] = rsc[4];
                        bss->rsc[id][2] = rsc[3];
@@ -369,10 +401,11 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len,
                        bss->rsc[id][4] = rsc[1];
                        bss->rsc[id][5] = rsc[0];
                        bss->gtk_idx = id;
+                       sta->gtk_idx = id;
                        wpa_hexdump(MSG_DEBUG, "RSC", bss->rsc[id], 6);
                } else {
-                       wpa_printf(MSG_INFO, "Invalid GTK KDE length %u",
-                                  (unsigned) ie.gtk_len);
+                       add_note(wt, MSG_INFO, "Invalid GTK KDE length %u",
+                                (unsigned) ie.gtk_len);
                }
        }
 
@@ -383,8 +416,8 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len,
                        u16 id;
                        id = WPA_GET_LE16(ie.igtk);
                        if (id > 5) {
-                               wpa_printf(MSG_INFO, "Unexpected IGTK KeyID "
-                                          "%u", id);
+                               add_note(wt, MSG_INFO,
+                                        "Unexpected IGTK KeyID %u", id);
                        } else {
                                const u8 *ipn;
                                wpa_printf(MSG_DEBUG, "IGTK KeyID %u", id);
@@ -403,8 +436,8 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len,
                                bss->igtk_idx = id;
                        }
                } else {
-                       wpa_printf(MSG_INFO, "Invalid IGTK KDE length %u",
-                                  (unsigned) ie.igtk_len);
+                       add_note(wt, MSG_INFO, "Invalid IGTK KDE length %u",
+                                (unsigned) ie.igtk_len);
                }
        }
 }
@@ -417,7 +450,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        struct wlantest_sta *sta;
        const struct ieee802_1x_hdr *eapol;
        const struct wpa_eapol_key *hdr;
-       const u8 *key_data, *kck;
+       const u8 *key_data, *kck, *kek;
        int recalc = 0;
        u16 key_info, ver;
        u8 *decrypted_buf = NULL;
@@ -439,8 +472,8 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        key_info = WPA_GET_BE16(hdr->key_info);
 
        if (os_memcmp(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN) != 0) {
-               wpa_printf(MSG_INFO, "EAPOL-Key ANonce mismatch between 1/4 "
-                          "and 3/4");
+               add_note(wt, MSG_INFO,
+                        "EAPOL-Key ANonce mismatch between 1/4 and 3/4");
                recalc = 1;
        }
        os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN);
@@ -450,35 +483,39 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        }
 
        if (!sta->ptk_set && !sta->tptk_set) {
-               wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 3/4");
+               add_note(wt, MSG_DEBUG,
+                        "No PTK known to process EAPOL-Key 3/4");
                return;
        }
 
+       kek = sta->ptk.kek;
        kck = sta->ptk.kck;
        if (sta->tptk_set) {
-               wpa_printf(MSG_DEBUG, "Use TPTK for validation EAPOL-Key MIC");
+               add_note(wt, MSG_DEBUG,
+                        "Use TPTK for validation EAPOL-Key MIC");
                kck = sta->tptk.kck;
+               kek = sta->tptk.kek;
        }
        if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
-               wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
+               add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
                return;
        }
-       wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 3/4");
+       add_note(wt, MSG_DEBUG, "Valid MIC found in EAPOL-Key 3/4");
 
        key_data = (const u8 *) (hdr + 1);
        if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
                if (sta->proto & WPA_PROTO_RSN)
-                       wpa_printf(MSG_INFO, "EAPOL-Key 3/4 without "
-                                  "EncrKeyData bit");
+                       add_note(wt, MSG_INFO,
+                                "EAPOL-Key 3/4 without EncrKeyData bit");
                decrypted = key_data;
                decrypted_len = WPA_GET_BE16(hdr->key_data_length);
        } else {
                ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-               decrypted_buf = decrypt_eapol_key_data(sta->ptk.kek, ver, hdr,
+               decrypted_buf = decrypt_eapol_key_data(wt, kek, ver, hdr,
                                                       &decrypted_len);
                if (decrypted_buf == NULL) {
-                       wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key "
-                                  "Data");
+                       add_note(wt, MSG_INFO,
+                                "Failed to decrypt EAPOL-Key Key Data");
                        return;
                }
                decrypted = decrypted_buf;
@@ -526,7 +563,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        }
 
        if (wpa_supplicant_parse_ies(decrypted, decrypted_len, &ie) < 0) {
-               wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data");
+               add_note(wt, MSG_INFO, "Failed to parse EAPOL-Key Key Data");
                os_free(decrypted_buf);
                return;
        }
@@ -534,9 +571,10 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        if ((ie.wpa_ie &&
             os_memcmp(ie.wpa_ie, bss->wpaie, ie.wpa_ie_len) != 0) ||
            (ie.wpa_ie == NULL && bss->wpaie[0])) {
-               wpa_printf(MSG_INFO, "Mismatch in WPA IE between "
-                          "EAPOL-Key 3/4 and Beacon/Probe Response "
-                          "from " MACSTR, MAC2STR(bss->bssid));
+               add_note(wt, MSG_INFO,
+                        "Mismatch in WPA IE between EAPOL-Key 3/4 and "
+                        "Beacon/Probe Response from " MACSTR,
+                        MAC2STR(bss->bssid));
                wpa_hexdump(MSG_INFO, "WPA IE in EAPOL-Key",
                            ie.wpa_ie, ie.wpa_ie_len);
                wpa_hexdump(MSG_INFO, "WPA IE in Beacon/Probe "
@@ -548,9 +586,9 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
        if ((ie.rsn_ie &&
             os_memcmp(ie.rsn_ie, bss->rsnie, ie.rsn_ie_len) != 0) ||
            (ie.rsn_ie == NULL && bss->rsnie[0])) {
-               wpa_printf(MSG_INFO, "Mismatch in RSN IE between "
-                          "EAPOL-Key 3/4 and Beacon/Probe Response "
-                          "from " MACSTR, MAC2STR(bss->bssid));
+               add_note(wt, MSG_INFO, "Mismatch in RSN IE between EAPOL-Key "
+                        "3/4 and Beacon/Probe Response from " MACSTR,
+                        MAC2STR(bss->bssid));
                wpa_hexdump(MSG_INFO, "RSN IE in EAPOL-Key",
                            ie.rsn_ie, ie.rsn_ie_len);
                wpa_hexdump(MSG_INFO, "RSN IE in (Re)Association "
@@ -559,7 +597,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
                            bss->rsnie[0] ? 2 + bss->rsnie[1] : 0);
        }
 
-       learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc);
+       learn_kde_keys(wt, bss, sta, decrypted, decrypted_len, hdr->key_rsc);
        os_free(decrypted_buf);
 }
 
@@ -624,7 +662,6 @@ static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
        struct wlantest_sta *sta;
        const struct ieee802_1x_hdr *eapol;
        const struct wpa_eapol_key *hdr;
-       const u8 *key_data;
        u16 key_info, ver;
        u8 *decrypted;
        size_t decrypted_len = 0;
@@ -655,14 +692,13 @@ static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
        }
        wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 1/2");
 
-       key_data = (const u8 *) (hdr + 1);
        if (sta->proto & WPA_PROTO_RSN &&
            !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
                wpa_printf(MSG_INFO, "EAPOL-Key 1/2 without EncrKeyData bit");
                return;
        }
        ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-       decrypted = decrypt_eapol_key_data(sta->ptk.kek, ver, hdr,
+       decrypted = decrypt_eapol_key_data(wt, sta->ptk.kek, ver, hdr,
                                           &decrypted_len);
        if (decrypted == NULL) {
                wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key Data");
@@ -709,7 +745,8 @@ static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
                                     decrypted, plain_len);
        }
        if (sta->proto & WPA_PROTO_RSN)
-               learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc);
+               learn_kde_keys(wt, bss, sta, decrypted, decrypted_len,
+                              hdr->key_rsc);
        else {
                int klen = bss->group_cipher == WPA_CIPHER_TKIP ? 32 : 16;
                if (decrypted_len == klen) {
index 2070159..19b338b 100644 (file)
@@ -2,14 +2,8 @@
  * Received Data frame processing for IPv4 packets
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -20,8 +14,8 @@
 #include "wlantest.h"
 
 
-static void ping_update(struct wlantest_sta *sta, int req, u32 src, u32 dst,
-                       u16 id, u16 seq)
+static void ping_update(struct wlantest *wt, struct wlantest_sta *sta, int req,
+                       u32 src, u32 dst, u16 id, u16 seq)
 {
        if (req) {
                sta->icmp_echo_req_src = src;
@@ -40,8 +34,8 @@ static void ping_update(struct wlantest_sta *sta, int req, u32 src, u32 dst,
                    sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX] == 0)
                        sta->counters[
                                WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC]++;
-               wpa_printf(MSG_DEBUG, "ICMP echo (ping) match for STA " MACSTR,
-                          MAC2STR(sta->addr));
+               add_note(wt, MSG_DEBUG, "ICMP echo (ping) match for STA "
+                        MACSTR, MAC2STR(sta->addr));
        }
 }
 
@@ -74,15 +68,15 @@ static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
        addr.s_addr = dst;
        snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
        addr.s_addr = src;
-       wpa_printf(MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
-                  hdr->type == ICMP_ECHO ? "request" : "response",
-                  inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
-                  peer_addr ? " [DL]" : "");
+       add_note(wt, MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
+                hdr->type == ICMP_ECHO ? "request" : "response",
+                inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
+                peer_addr ? " [DL]" : "");
 
        bss = bss_find(wt, bssid);
        if (bss == NULL) {
-               wpa_printf(MSG_INFO, "No BSS " MACSTR " known for ICMP packet",
-                          MAC2STR(bssid));
+               add_note(wt, MSG_INFO, "No BSS " MACSTR
+                        " known for ICMP packet", MAC2STR(bssid));
                return;
        }
 
@@ -91,14 +85,30 @@ static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
 
        sta = sta_find(bss, sta_addr);
        if (sta == NULL) {
-               wpa_printf(MSG_INFO, "No STA " MACSTR " known for ICMP packet",
-                          MAC2STR(sta_addr));
+               add_note(wt, MSG_INFO, "No STA " MACSTR
+                        " known for ICMP packet", MAC2STR(sta_addr));
                return;
        }
 
-       ping_update(sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
+       ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
        if (peer_addr && (sta = sta_find(bss, peer_addr)))
-               ping_update(sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
+               ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
+}
+
+
+static int hwsim_test_packet(const u8 *data, size_t len)
+{
+       size_t i;
+
+       if (len != 1500 - 14)
+               return 0;
+
+       for (i = 0; i < len; i++) {
+               if (data[i] != (i & 0xff))
+                       return 0;
+       }
+
+       return 1;
 }
 
 
@@ -115,24 +125,28 @@ void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
        if (len < sizeof(*ip))
                return;
        if (ip->version != 4) {
-               wpa_printf(MSG_DEBUG, "Unexpected IP protocol version %u in "
-                          "IPv4 packet (bssid=" MACSTR " str=" MACSTR
-                          " dst=" MACSTR ")", ip->version, MAC2STR(bssid),
-                          MAC2STR(src), MAC2STR(dst));
+               if (hwsim_test_packet(data, len)) {
+                       add_note(wt, MSG_INFO, "hwsim_test package");
+                       return;
+               }
+               add_note(wt, MSG_DEBUG, "Unexpected IP protocol version %u in "
+                        "IPv4 packet (bssid=" MACSTR " str=" MACSTR
+                        " dst=" MACSTR ")", ip->version, MAC2STR(bssid),
+                        MAC2STR(src), MAC2STR(dst));
                return;
        }
        if (ip->ihl * 4 < sizeof(*ip)) {
-               wpa_printf(MSG_DEBUG, "Unexpected IP header length %u in "
-                          "IPv4 packet (bssid=" MACSTR " str=" MACSTR
-                          " dst=" MACSTR ")", ip->ihl, MAC2STR(bssid),
-                          MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_DEBUG, "Unexpected IP header length %u in "
+                        "IPv4 packet (bssid=" MACSTR " str=" MACSTR
+                        " dst=" MACSTR ")", ip->ihl, MAC2STR(bssid),
+                        MAC2STR(src), MAC2STR(dst));
                return;
        }
        if (ip->ihl * 4 > len) {
-               wpa_printf(MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) in "
-                          "IPv4 packet (bssid=" MACSTR " str=" MACSTR
-                          " dst=" MACSTR ")", ip->ihl, (unsigned) len,
-                          MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) "
+                        "in IPv4 packet (bssid=" MACSTR " str=" MACSTR
+                        " dst=" MACSTR ")", ip->ihl, (unsigned) len,
+                        MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
                return;
        }
 
index c7a9390..a2df0e9 100644 (file)
@@ -2,14 +2,8 @@
  * Received Management frame processing
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -71,8 +65,8 @@ static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
                                   &elems, 0) == ParseFailed) {
                if (bss->parse_error_reported)
                        return;
-               wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Invalid IEs in a Beacon frame from "
+                        MACSTR, MAC2STR(mgmt->sa));
                bss->parse_error_reported = 1;
                return;
        }
@@ -98,8 +92,8 @@ static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
                                   &elems, 0) == ParseFailed) {
                if (bss->parse_error_reported)
                        return;
-               wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
-                          "from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Invalid IEs in a Probe Response frame "
+                        "from " MACSTR, MAC2STR(mgmt->sa));
                bss->parse_error_reported = 1;
                return;
        }
@@ -127,8 +121,8 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
                return;
 
        if (len < 24 + 6) {
-               wpa_printf(MSG_INFO, "Too short Authentication frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Authentication frame from "
+                        MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -142,9 +136,9 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
 
        if (alg == 0 && trans == 2 && status == 0) {
                if (sta->state == STATE1) {
-                       wpa_printf(MSG_DEBUG, "STA " MACSTR
-                                  " moved to State 2 with " MACSTR,
-                                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+                       add_note(wt, MSG_DEBUG, "STA " MACSTR
+                                " moved to State 2 with " MACSTR,
+                                MAC2STR(sta->addr), MAC2STR(bss->bssid));
                        sta->state = STATE2;
                }
        }
@@ -156,28 +150,29 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
 }
 
 
-static void deauth_all_stas(struct wlantest_bss *bss)
+static void deauth_all_stas(struct wlantest *wt, struct wlantest_bss *bss)
 {
        struct wlantest_sta *sta;
        dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
                if (sta->state == STATE1)
                        continue;
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 1 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 1 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE1;
        }
 }
 
 
-static void tdls_link_down(struct wlantest_bss *bss, struct wlantest_sta *sta)
+static void tdls_link_down(struct wlantest *wt, struct wlantest_bss *bss,
+                          struct wlantest_sta *sta)
 {
        struct wlantest_tdls *tdls;
        dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
                if ((tdls->init == sta || tdls->resp == sta) && tdls->link_up)
                {
-                       wpa_printf(MSG_DEBUG, "TDLS: Set link down based on "
-                                  "STA deauth/disassoc");
+                       add_note(wt, MSG_DEBUG, "TDLS: Set link down based on "
+                                "STA deauth/disassoc");
                        tdls->link_up = 0;
                }
        }
@@ -202,8 +197,8 @@ static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
                sta = sta_get(bss, mgmt->sa);
 
        if (len < 24 + 2) {
-               wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Deauthentication frame from "
+                        MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -216,7 +211,7 @@ static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
 
        if (sta == NULL) {
                if (valid && mgmt->da[0] == 0xff)
-                       deauth_all_stas(bss);
+                       deauth_all_stas(wt, bss);
                return;
        }
 
@@ -238,19 +233,19 @@ static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
                              WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX]++;
 
        if (!valid) {
-               wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
-                          "since Disassociation frame was not protected "
-                          "correctly", MAC2STR(sta->addr));
+               add_note(wt, MSG_INFO, "Do not change STA " MACSTR " State "
+                        "since Disassociation frame was not protected "
+                        "correctly", MAC2STR(sta->addr));
                return;
        }
 
        if (sta->state != STATE1) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 1 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 1 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE1;
        }
-       tdls_link_down(bss, sta);
+       tdls_link_down(wt, bss, sta);
 }
 
 
@@ -270,8 +265,8 @@ static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
                return;
 
        if (len < 24 + 4) {
-               wpa_printf(MSG_INFO, "Too short Association Request frame "
-                          "from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Association Request frame "
+                        "from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -286,8 +281,8 @@ static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
        if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
                                   len - (mgmt->u.assoc_req.variable - data),
                                   &elems, 0) == ParseFailed) {
-               wpa_printf(MSG_INFO, "Invalid IEs in Association Request "
-                          "frame from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Invalid IEs in Association Request "
+                        "frame from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -321,8 +316,8 @@ static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
                return;
 
        if (len < 24 + 6) {
-               wpa_printf(MSG_INFO, "Too short Association Response frame "
-                          "from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Association Response frame "
+                        "from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -341,17 +336,17 @@ static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
                size_t ies_len = len - (mgmt->u.assoc_resp.variable - data);
                if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
                    ParseFailed) {
-                       wpa_printf(MSG_INFO, "Failed to parse IEs in "
-                                  "AssocResp from " MACSTR,
-                                  MAC2STR(mgmt->sa));
+                       add_note(wt, MSG_INFO, "Failed to parse IEs in "
+                                "AssocResp from " MACSTR,
+                                MAC2STR(mgmt->sa));
                } else if (elems.timeout_int == NULL ||
                           elems.timeout_int_len != 5 ||
                           elems.timeout_int[0] !=
                           WLAN_TIMEOUT_ASSOC_COMEBACK) {
-                       wpa_printf(MSG_INFO, "No valid Timeout Interval IE "
-                                  "with Assoc Comeback time in AssocResp "
-                                  "(status=30) from " MACSTR,
-                                  MAC2STR(mgmt->sa));
+                       add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
+                                "with Assoc Comeback time in AssocResp "
+                                "(status=30) from " MACSTR,
+                                MAC2STR(mgmt->sa));
                } else {
                        sta->counters[
                                WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK]++;
@@ -362,21 +357,22 @@ static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
                return;
 
        if ((aid & 0xc000) != 0xc000) {
-               wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
-                          "in Association Response from " MACSTR,
-                          MAC2STR(mgmt->sa));
+               add_note(wt, MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
+                        "in Association Response from " MACSTR,
+                        MAC2STR(mgmt->sa));
        }
        sta->aid = aid & 0xc000;
 
        if (sta->state < STATE2) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
-                          "getting associated", MAC2STR(sta->addr));
+               add_note(wt, MSG_DEBUG,
+                        "STA " MACSTR " was not in State 2 when "
+                        "getting associated", MAC2STR(sta->addr));
        }
 
        if (sta->state < STATE3) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 3 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 3 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE3;
        }
 }
@@ -399,8 +395,8 @@ static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
                return;
 
        if (len < 24 + 4 + ETH_ALEN) {
-               wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
-                          "from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Reassociation Request frame "
+                        "from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -416,8 +412,8 @@ static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
        if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
                                   len - (mgmt->u.reassoc_req.variable - data),
                                   &elems, 0) == ParseFailed) {
-               wpa_printf(MSG_INFO, "Invalid IEs in Reassociation Request "
-                          "frame from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Invalid IEs in Reassociation Request "
+                        "frame from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -453,8 +449,8 @@ static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
                return;
 
        if (len < 24 + 6) {
-               wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
-                          "from " MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Reassociation Response frame "
+                        "from " MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -473,17 +469,17 @@ static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
                size_t ies_len = len - (mgmt->u.reassoc_resp.variable - data);
                if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
                    ParseFailed) {
-                       wpa_printf(MSG_INFO, "Failed to parse IEs in "
-                                  "ReassocResp from " MACSTR,
-                                  MAC2STR(mgmt->sa));
+                       add_note(wt, MSG_INFO, "Failed to parse IEs in "
+                                "ReassocResp from " MACSTR,
+                                MAC2STR(mgmt->sa));
                } else if (elems.timeout_int == NULL ||
                           elems.timeout_int_len != 5 ||
                           elems.timeout_int[0] !=
                           WLAN_TIMEOUT_ASSOC_COMEBACK) {
-                       wpa_printf(MSG_INFO, "No valid Timeout Interval IE "
-                                  "with Assoc Comeback time in ReassocResp "
-                                  "(status=30) from " MACSTR,
-                                  MAC2STR(mgmt->sa));
+                       add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
+                                "with Assoc Comeback time in ReassocResp "
+                                "(status=30) from " MACSTR,
+                                MAC2STR(mgmt->sa));
                } else {
                        sta->counters[
                                WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK]++;
@@ -494,35 +490,36 @@ static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
                return;
 
        if ((aid & 0xc000) != 0xc000) {
-               wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
-                          "in Reassociation Response from " MACSTR,
-                          MAC2STR(mgmt->sa));
+               add_note(wt, MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
+                        "in Reassociation Response from " MACSTR,
+                        MAC2STR(mgmt->sa));
        }
        sta->aid = aid & 0xc000;
 
        if (sta->state < STATE2) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
-                          "getting associated", MAC2STR(sta->addr));
+               add_note(wt, MSG_DEBUG,
+                        "STA " MACSTR " was not in State 2 when "
+                        "getting associated", MAC2STR(sta->addr));
        }
 
        if (sta->state < STATE3) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 3 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 3 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE3;
        }
 }
 
 
-static void disassoc_all_stas(struct wlantest_bss *bss)
+static void disassoc_all_stas(struct wlantest *wt, struct wlantest_bss *bss)
 {
        struct wlantest_sta *sta;
        dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
                if (sta->state <= STATE2)
                        continue;
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 2 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 2 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE2;
        }
 }
@@ -546,8 +543,8 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
                sta = sta_get(bss, mgmt->sa);
 
        if (len < 24 + 2) {
-               wpa_printf(MSG_INFO, "Too short Disassociation frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Disassociation frame from "
+                        MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 
@@ -560,7 +557,7 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
 
        if (sta == NULL) {
                if (valid && mgmt->da[0] == 0xff)
-                       disassoc_all_stas(bss);
+                       disassoc_all_stas(wt, bss);
                return;
        }
 
@@ -584,24 +581,25 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
                              WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX]++;
 
        if (!valid) {
-               wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
-                          "since Disassociation frame was not protected "
-                          "correctly", MAC2STR(sta->addr));
+               add_note(wt, MSG_INFO, "Do not change STA " MACSTR " State "
+                        "since Disassociation frame was not protected "
+                        "correctly", MAC2STR(sta->addr));
                return;
        }
 
        if (sta->state < STATE2) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 or 3 "
-                          "when getting disassociated", MAC2STR(sta->addr));
+               add_note(wt, MSG_DEBUG,
+                        "STA " MACSTR " was not in State 2 or 3 "
+                        "when getting disassociated", MAC2STR(sta->addr));
        }
 
        if (sta->state > STATE2) {
-               wpa_printf(MSG_DEBUG, "STA " MACSTR
-                          " moved to State 2 with " MACSTR,
-                          MAC2STR(sta->addr), MAC2STR(bss->bssid));
+               add_note(wt, MSG_DEBUG, "STA " MACSTR
+                        " moved to State 2 with " MACSTR,
+                        MAC2STR(sta->addr), MAC2STR(bss->bssid));
                sta->state = STATE2;
        }
-       tdls_link_down(bss, sta);
+       tdls_link_down(wt, bss, sta);
 }
 
 
@@ -618,10 +616,10 @@ static void rx_mgmt_action_sa_query_req(struct wlantest *wt,
                id = sta->ap_sa_query_tr;
        else
                id = sta->sta_sa_query_tr;
-       wpa_printf(MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR
-                  " (trans_id=%02x%02x)%s",
-                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
-                  valid ? "" : " (invalid protection)");
+       add_note(wt, MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR
+                " (trans_id=%02x%02x)%s",
+                MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
+                valid ? "" : " (invalid protection)");
        os_memcpy(id, mgmt->u.action.u.sa_query_req.trans_id, 2);
        if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
                sta->counters[valid ?
@@ -649,11 +647,11 @@ static void rx_mgmt_action_sa_query_resp(struct wlantest *wt,
        else
                id = sta->ap_sa_query_tr;
        match = os_memcmp(rx_id, id, 2) == 0;
-       wpa_printf(MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR
-                  " (trans_id=%02x%02x; %s)%s",
-                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
-                  match ? "match" : "mismatch",
-                  valid ? "" : " (invalid protection)");
+       add_note(wt, MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR
+                " (trans_id=%02x%02x; %s)%s",
+                MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
+                match ? "match" : "mismatch",
+                valid ? "" : " (invalid protection)");
        if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
                sta->counters[(valid && match) ?
                              WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX :
@@ -671,16 +669,16 @@ static void rx_mgmt_action_sa_query(struct wlantest *wt,
                                    size_t len, int valid)
 {
        if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
-               wpa_printf(MSG_INFO, "Too short SA Query frame from " MACSTR,
-                          MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short SA Query frame from " MACSTR,
+                        MAC2STR(mgmt->sa));
                return;
        }
 
        if (len > 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
                size_t elen = len - (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN);
-               wpa_printf(MSG_INFO, "Unexpected %u octets of extra data at "
-                          "the end of SA Query frame from " MACSTR,
-                          (unsigned) elen, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Unexpected %u octets of extra data at "
+                        "the end of SA Query frame from " MACSTR,
+                        (unsigned) elen, MAC2STR(mgmt->sa));
                wpa_hexdump(MSG_INFO, "SA Query extra data",
                            ((const u8 *) mgmt) + len - elen, elen);
        }
@@ -693,10 +691,10 @@ static void rx_mgmt_action_sa_query(struct wlantest *wt,
                rx_mgmt_action_sa_query_resp(wt, sta, mgmt, len, valid);
                break;
        default:
-               wpa_printf(MSG_INFO, "Unexpected SA Query action value %u "
-                          "from " MACSTR,
-                          mgmt->u.action.u.sa_query_req.action,
-                          MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Unexpected SA Query action value %u "
+                        "from " MACSTR,
+                        mgmt->u.action.u.sa_query_req.action,
+                        MAC2STR(mgmt->sa));
        }
 }
 
@@ -710,11 +708,11 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
 
        mgmt = (const struct ieee80211_mgmt *) data;
        if (mgmt->da[0] & 0x01) {
-               wpa_printf(MSG_DEBUG, "Group addressed Action frame: DA="
-                          MACSTR " SA=" MACSTR " BSSID=" MACSTR
-                          " category=%u",
-                          MAC2STR(mgmt->da), MAC2STR(mgmt->sa),
-                          MAC2STR(mgmt->bssid), mgmt->u.action.category);
+               add_note(wt, MSG_DEBUG, "Group addressed Action frame: DA="
+                        MACSTR " SA=" MACSTR " BSSID=" MACSTR
+                        " category=%u",
+                        MAC2STR(mgmt->da), MAC2STR(mgmt->sa),
+                        MAC2STR(mgmt->bssid), mgmt->u.action.category);
                return; /* Ignore group addressed Action frames for now */
        }
        bss = bss_get(wt, mgmt->bssid);
@@ -728,8 +726,8 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
                return;
 
        if (len < 24 + 1) {
-               wpa_printf(MSG_INFO, "Too short Action frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Too short Action frame from " MACSTR,
+                        MAC2STR(mgmt->sa));
                return;
        }
 
@@ -741,9 +739,9 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
 
        if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
            sta->state < STATE3) {
-               wpa_printf(MSG_INFO, "Action frame sent when STA is not in "
-                          "State 3 (SA=" MACSTR " DATA=" MACSTR ")",
-                          MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+               add_note(wt, MSG_INFO, "Action frame sent when STA is not in "
+                        "State 3 (SA=" MACSTR " DATA=" MACSTR ")",
+                        MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
        }
 
        switch (mgmt->u.action.category) {
@@ -819,9 +817,9 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
            data[len - 17] != 16) {
                /* No MMIE */
                if (bss->rsn_capab & WPA_CAPABILITY_MFPC) {
-                       wpa_printf(MSG_INFO, "Robust group-addressed "
-                                  "management frame sent without BIP by "
-                                  MACSTR, MAC2STR(mgmt->sa));
+                       add_note(wt, MSG_INFO, "Robust group-addressed "
+                                "management frame sent without BIP by "
+                                MACSTR, MAC2STR(mgmt->sa));
                        bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
                        return -1;
                }
@@ -831,13 +829,13 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
        mmie = data + len - 16;
        keyid = WPA_GET_LE16(mmie);
        if (keyid & 0xf000) {
-               wpa_printf(MSG_INFO, "MMIE KeyID reserved bits not zero "
-                          "(%04x) from " MACSTR, keyid, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "MMIE KeyID reserved bits not zero "
+                        "(%04x) from " MACSTR, keyid, MAC2STR(mgmt->sa));
                keyid &= 0x0fff;
        }
        if (keyid < 4 || keyid > 5) {
-               wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
-                          keyid, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
+                        keyid, MAC2STR(mgmt->sa));
                bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
                return 0;
        }
@@ -846,25 +844,25 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
        wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
 
        if (!bss->igtk_set[keyid]) {
-               wpa_printf(MSG_DEBUG, "No IGTK known to validate BIP frame");
+               add_note(wt, MSG_DEBUG, "No IGTK known to validate BIP frame");
                return 0;
        }
 
        if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) <= 0) {
-               wpa_printf(MSG_INFO, "BIP replay detected: SA=" MACSTR,
-                          MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "BIP replay detected: SA=" MACSTR,
+                        MAC2STR(mgmt->sa));
                wpa_hexdump(MSG_INFO, "RX IPN", mmie + 2, 6);
                wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
        }
 
        if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
-               wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Invalid MMIE MIC in a frame from "
+                        MACSTR, MAC2STR(mgmt->sa));
                bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
                return -1;
        }
 
-       wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
+       add_note(wt, MSG_DEBUG, "Valid MMIE MIC");
        os_memcpy(bss->ipn[keyid], mmie + 2, 6);
        bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++;
 
@@ -896,7 +894,7 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
        else
                sta = sta_get(bss, hdr->addr1);
        if (sta == NULL || !sta->ptk_set) {
-               wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame");
+               add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
                return NULL;
        }
 
@@ -904,22 +902,22 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
                return NULL;
 
        if (!(data[24 + 3] & 0x20)) {
-               wpa_printf(MSG_INFO, "Expected CCMP frame from " MACSTR
-                          " did not have ExtIV bit set to 1",
-                          MAC2STR(hdr->addr2));
+               add_note(wt, MSG_INFO, "Expected CCMP frame from " MACSTR
+                        " did not have ExtIV bit set to 1",
+                        MAC2STR(hdr->addr2));
                return NULL;
        }
 
        if (data[24 + 2] != 0 || (data[24 + 3] & 0x1f) != 0) {
-               wpa_printf(MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
-                          "non-zero reserved bit", MAC2STR(hdr->addr2));
+               add_note(wt, MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
+                        "non-zero reserved bit", MAC2STR(hdr->addr2));
        }
 
        keyid = data[24 + 3] >> 6;
        if (keyid != 0) {
-               wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in "
-                          "individually addressed Management frame from "
-                          MACSTR, keyid, MAC2STR(hdr->addr2));
+               add_note(wt, MSG_INFO, "Unexpected non-zero KeyID %d in "
+                        "individually addressed Management frame from "
+                        MACSTR, keyid, MAC2STR(hdr->addr2));
        }
 
        if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
@@ -930,12 +928,12 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
        ccmp_get_pn(pn, data + 24);
        if (os_memcmp(pn, rsc, 6) <= 0) {
                u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
-               wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
-                          " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
-                          MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
-                          MAC2STR(hdr->addr3),
-                          WLAN_GET_SEQ_SEQ(seq_ctrl),
-                          WLAN_GET_SEQ_FRAG(seq_ctrl));
+               add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
+                        " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
+                        MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+                        MAC2STR(hdr->addr3),
+                        WLAN_GET_SEQ_SEQ(seq_ctrl),
+                        WLAN_GET_SEQ_FRAG(seq_ctrl));
                wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
                wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
        }
@@ -986,9 +984,9 @@ static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
        if ((sta->rsn_capab & WPA_CAPABILITY_MFPC) &&
            (sta->state == STATE3 ||
             WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION)) {
-               wpa_printf(MSG_INFO, "Robust individually-addressed "
-                          "management frame sent without CCMP by "
-                          MACSTR, MAC2STR(mgmt->sa));
+               add_note(wt, MSG_INFO, "Robust individually-addressed "
+                        "management frame sent without CCMP by "
+                        MACSTR, MAC2STR(mgmt->sa));
                return -1;
        }
 
@@ -1111,8 +1109,8 @@ static void rx_mgmt_deauth_ack(struct wlantest *wt,
        if (sta == NULL)
                return;
 
-       wpa_printf(MSG_DEBUG, "DEAUTH from " MACSTR " acknowledged by " MACSTR,
-                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+       add_note(wt, MSG_DEBUG, "DEAUTH from " MACSTR " acknowledged by "
+                MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
        if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
                int c;
                c = wt->last_mgmt_valid ?
@@ -1141,8 +1139,8 @@ static void rx_mgmt_disassoc_ack(struct wlantest *wt,
        if (sta == NULL)
                return;
 
-       wpa_printf(MSG_DEBUG, "DISASSOC from " MACSTR " acknowledged by "
-                  MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+       add_note(wt, MSG_DEBUG, "DISASSOC from " MACSTR " acknowledged by "
+                MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
        if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
                int c;
                c = wt->last_mgmt_valid ?
index f2e2ac7..d9247c1 100644 (file)
@@ -2,14 +2,8 @@
  * Received Data frame processing for TDLS packets
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -34,11 +28,11 @@ static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid,
        if (bss == NULL && bssid) {
                bss = bss_find(wt, bssid);
                if (bss)
-                       wpa_printf(MSG_INFO, "TDLS: Incorrect BSSID " MACSTR
-                                  " in LinkId?! (init=" MACSTR " resp="
-                                  MACSTR ")",
-                                  MAC2STR(linkid), MAC2STR(linkid + ETH_ALEN),
-                                  MAC2STR(linkid + 2 * ETH_ALEN));
+                       add_note(wt, MSG_INFO, "TDLS: Incorrect BSSID " MACSTR
+                                " in LinkId?! (init=" MACSTR " resp="
+                                MACSTR ")",
+                                MAC2STR(linkid), MAC2STR(linkid + ETH_ALEN),
+                                MAC2STR(linkid + 2 * ETH_ALEN));
        }
        if (bss == NULL)
                return NULL;
@@ -59,6 +53,12 @@ static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid,
        if (!create_new)
                return NULL;
 
+       add_note(wt, MSG_DEBUG, "Add new TDLS link context: initiator " MACSTR
+                " responder " MACSTR " BSSID " MACSTR,
+                MAC2STR(linkid + ETH_ALEN),
+                MAC2STR(linkid + 2 * ETH_ALEN),
+                MAC2STR(bssid));
+
        tdls = os_zalloc(sizeof(*tdls));
        if (tdls == NULL)
                return NULL;
@@ -131,8 +131,8 @@ static int tdls_derive_tpk(struct wlantest_tdls *tdls, const u8 *bssid,
 }
 
 
-static int tdls_verify_mic(struct wlantest_tdls *tdls, u8 trans_seq,
-                          struct ieee802_11_elems *elems)
+static int tdls_verify_mic(struct wlantest *wt, struct wlantest_tdls *tdls,
+                          u8 trans_seq, struct ieee802_11_elems *elems)
 {
        u8 *buf, *pos;
        int len;
@@ -187,10 +187,10 @@ static int tdls_verify_mic(struct wlantest_tdls *tdls, u8 trans_seq,
        rx_ftie = (const struct rsn_ftie *) elems->ftie;
 
        if (os_memcmp(mic, rx_ftie->mic, 16) == 0) {
-               wpa_printf(MSG_DEBUG, "TDLS: Valid MIC");
+               add_note(wt, MSG_DEBUG, "TDLS: Valid MIC");
                return 0;
        }
-       wpa_printf(MSG_DEBUG, "TDLS: Invalid MIC");
+       add_note(wt, MSG_DEBUG, "TDLS: Invalid MIC");
        return -1;
 }
 
@@ -202,10 +202,11 @@ static void rx_data_tdls_setup_request(struct wlantest *wt, const u8 *bssid,
 {
        struct ieee802_11_elems elems;
        struct wlantest_tdls *tdls;
+       u8 linkid[3 * ETH_ALEN];
 
        if (len < 3) {
-               wpa_printf(MSG_INFO, "Too short TDLS Setup Request " MACSTR
-                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_INFO, "Too short TDLS Setup Request " MACSTR
+                        " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
                return;
        }
        wpa_printf(MSG_DEBUG, "TDLS Setup Request " MACSTR " -> "
@@ -222,7 +223,20 @@ static void rx_data_tdls_setup_request(struct wlantest *wt, const u8 *bssid,
        if (tdls) {
                tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_REQ]++;
                tdls->dialog_token = data[0];
+               if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) {
+                       const struct rsn_ftie *f;
+                       f = (const struct rsn_ftie *) elems.ftie;
+                       os_memcpy(tdls->inonce, f->snonce, WPA_NONCE_LEN);
+               }
        }
+
+       /* Check whether reverse direction context exists already */
+       os_memcpy(linkid, bssid, ETH_ALEN);
+       os_memcpy(linkid + ETH_ALEN, dst, ETH_ALEN);
+       os_memcpy(linkid + 2 * ETH_ALEN, src, ETH_ALEN);
+       tdls = get_tdls(wt, linkid, 0, bssid);
+       if (tdls)
+               add_note(wt, MSG_INFO, "Reverse direction TDLS context exists");
 }
 
 
@@ -236,8 +250,8 @@ static void rx_data_tdls_setup_response_failure(struct wlantest *wt,
        struct wlantest_sta *sta;
 
        if (status == WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_INFO, "TDLS: Invalid TDLS Setup Response from "
-                          MACSTR, MAC2STR(sta_addr));
+               add_note(wt, MSG_INFO, "TDLS: Invalid TDLS Setup Response from "
+                        MACSTR, MAC2STR(sta_addr));
                return;
        }
 
@@ -251,13 +265,13 @@ static void rx_data_tdls_setup_response_failure(struct wlantest *wt,
        dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
                if (tdls->resp == sta) {
                        if (dialog_token != tdls->dialog_token) {
-                               wpa_printf(MSG_DEBUG, "TDLS: Dialog token "
-                                          "mismatch in TDLS Setup Response "
-                                          "(failure)");
+                               add_note(wt, MSG_DEBUG, "TDLS: Dialog token "
+                                        "mismatch in TDLS Setup Response "
+                                        "(failure)");
                                break;
                        }
-                       wpa_printf(MSG_DEBUG, "TDLS: Found matching TDLS "
-                                  "setup session based on dialog token");
+                       add_note(wt, MSG_DEBUG, "TDLS: Found matching TDLS "
+                                "setup session based on dialog token");
                        tdls->counters[
                                WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL]++;
                        break;
@@ -276,8 +290,8 @@ static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid,
        struct wlantest_tdls *tdls;
 
        if (len < 3) {
-               wpa_printf(MSG_INFO, "Too short TDLS Setup Response " MACSTR
-                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_INFO, "Too short TDLS Setup Response " MACSTR
+                        " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
                return;
        }
        status = WPA_GET_LE16(data);
@@ -285,8 +299,8 @@ static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid,
                   MACSTR " (status %d)",
                   MAC2STR(src), MAC2STR(dst), status);
        if (len < 5 && status == 0) {
-               wpa_printf(MSG_INFO, "Too short TDLS Setup Response " MACSTR
-                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_INFO, "Too short TDLS Setup Response " MACSTR
+                        " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
                return;
        }
 
@@ -304,8 +318,10 @@ static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid,
                   MAC2STR(elems.link_id + 2 * ETH_ALEN));
 
        tdls = get_tdls(wt, elems.link_id, 1, bssid);
-       if (!tdls)
+       if (!tdls) {
+               add_note(wt, MSG_INFO, "No match TDLS context found");
                return;
+       }
        if (status)
                tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL]++;
        else
@@ -314,12 +330,22 @@ static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid,
        if (status != WLAN_STATUS_SUCCESS)
                return;
 
+       if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) {
+               const struct rsn_ftie *f;
+               f = (const struct rsn_ftie *) elems.ftie;
+               if (os_memcmp(tdls->inonce, f->snonce, WPA_NONCE_LEN) != 0) {
+                       add_note(wt, MSG_INFO, "Mismatch in TDLS initiator "
+                                "nonce");
+               }
+               os_memcpy(tdls->rnonce, f->anonce, WPA_NONCE_LEN);
+       }
+
        if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1)
                return;
-       if (tdls_verify_mic(tdls, 2, &elems) == 0) {
+       if (tdls_verify_mic(wt, tdls, 2, &elems) == 0) {
                tdls->dialog_token = data[2];
-               wpa_printf(MSG_DEBUG, "TDLS: Dialog Token for the link: %u",
-                          tdls->dialog_token);
+               add_note(wt, MSG_DEBUG, "TDLS: Dialog Token for the link: %u",
+                        tdls->dialog_token);
        }
 }
 
@@ -334,8 +360,8 @@ static void rx_data_tdls_setup_confirm_failure(struct wlantest *wt,
        struct wlantest_sta *sta;
 
        if (status == WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_INFO, "TDLS: Invalid TDLS Setup Confirm from "
-                          MACSTR, MAC2STR(src));
+               add_note(wt, MSG_INFO, "TDLS: Invalid TDLS Setup Confirm from "
+                        MACSTR, MAC2STR(src));
                return;
        }
 
@@ -349,13 +375,13 @@ static void rx_data_tdls_setup_confirm_failure(struct wlantest *wt,
        dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
                if (tdls->init == sta) {
                        if (dialog_token != tdls->dialog_token) {
-                               wpa_printf(MSG_DEBUG, "TDLS: Dialog token "
-                                          "mismatch in TDLS Setup Confirm "
-                                          "(failure)");
+                               add_note(wt, MSG_DEBUG, "TDLS: Dialog token "
+                                        "mismatch in TDLS Setup Confirm "
+                                        "(failure)");
                                break;
                        }
-                       wpa_printf(MSG_DEBUG, "TDLS: Found matching TDLS "
-                                  "setup session based on dialog token");
+                       add_note(wt, MSG_DEBUG, "TDLS: Found matching TDLS "
+                                "setup session based on dialog token");
                        tdls->counters[
                                WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++;
                        break;
@@ -375,8 +401,8 @@ static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid,
        u8 link_id[3 * ETH_ALEN];
 
        if (len < 3) {
-               wpa_printf(MSG_INFO, "Too short TDLS Setup Confirm " MACSTR
-                          " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
+               add_note(wt, MSG_INFO, "Too short TDLS Setup Confirm " MACSTR
+                        " -> " MACSTR, MAC2STR(src), MAC2STR(dst));
                return;
        }
        status = WPA_GET_LE16(data);
@@ -407,16 +433,29 @@ static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid,
        if (status != WLAN_STATUS_SUCCESS)
                return;
 
+       if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) {
+               const struct rsn_ftie *f;
+               f = (const struct rsn_ftie *) elems.ftie;
+               if (os_memcmp(tdls->inonce, f->snonce, WPA_NONCE_LEN) != 0) {
+                       add_note(wt, MSG_INFO, "Mismatch in TDLS initiator "
+                                "nonce");
+               }
+               if (os_memcmp(tdls->rnonce, f->anonce, WPA_NONCE_LEN) != 0) {
+                       add_note(wt, MSG_INFO, "Mismatch in TDLS responder "
+                                "nonce");
+               }
+       }
+
        tdls->link_up = 1;
        if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) {
                if (elems.ftie == NULL)
                        goto remove_reverse;
                return;
        }
-       if (tdls_verify_mic(tdls, 3, &elems) == 0) {
+       if (tdls_verify_mic(wt, tdls, 3, &elems) == 0) {
                tdls->dialog_token = data[2];
-               wpa_printf(MSG_DEBUG, "TDLS: Dialog Token for the link: %u",
-                          tdls->dialog_token);
+               add_note(wt, MSG_DEBUG, "TDLS: Link up - Dialog Token: %u",
+                        tdls->dialog_token);
        }
 
 remove_reverse:
@@ -431,13 +470,14 @@ remove_reverse:
        os_memcpy(link_id + 2 * ETH_ALEN, elems.link_id + ETH_ALEN, ETH_ALEN);
        tdls = get_tdls(wt, link_id, 0, bssid);
        if (tdls) {
-               wpa_printf(MSG_DEBUG, "TDLS: Remove reverse link entry");
+               add_note(wt, MSG_DEBUG, "TDLS: Remove reverse link entry");
                tdls_deinit(tdls);
        }
 }
 
 
-static int tdls_verify_mic_teardown(struct wlantest_tdls *tdls, u8 trans_seq,
+static int tdls_verify_mic_teardown(struct wlantest *wt,
+                                   struct wlantest_tdls *tdls, u8 trans_seq,
                                    const u8 *reason_code,
                                    struct ieee802_11_elems *elems)
 {
@@ -485,10 +525,10 @@ static int tdls_verify_mic_teardown(struct wlantest_tdls *tdls, u8 trans_seq,
        rx_ftie = (const struct rsn_ftie *) elems->ftie;
 
        if (os_memcmp(mic, rx_ftie->mic, 16) == 0) {
-               wpa_printf(MSG_DEBUG, "TDLS: Valid MIC");
+               add_note(wt, MSG_DEBUG, "TDLS: Valid MIC");
                return 0;
        }
-       wpa_printf(MSG_DEBUG, "TDLS: Invalid MIC");
+       add_note(wt, MSG_DEBUG, "TDLS: Invalid MIC");
        return -1;
 }
 
@@ -519,9 +559,11 @@ static void rx_data_tdls_teardown(struct wlantest *wt, const u8 *bssid,
 
        tdls = get_tdls(wt, elems.link_id, 1, bssid);
        if (tdls) {
+               if (tdls->link_up)
+                       add_note(wt, MSG_DEBUG, "TDLS: Link down");
                tdls->link_up = 0;
                tdls->counters[WLANTEST_TDLS_COUNTER_TEARDOWN]++;
-               tdls_verify_mic_teardown(tdls, 4, data, &elems);
+               tdls_verify_mic_teardown(wt, tdls, 4, data, &elems);
        }
 }
 
index 4b5d16d..115ef8a 100644 (file)
@@ -2,14 +2,8 @@
  * STA list
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
diff --git a/wlantest/test_vectors.c b/wlantest/test_vectors.c
new file mode 100644 (file)
index 0000000..6c716c4
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * test_vectors - IEEE 802.11 test vector generator
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "wlantest.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+
+
+static void test_vector_tkip(void)
+{
+       u8 tk[] = {
+               0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
+               0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34
+       };
+       u8 pn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+       u8 frame[] = {
+               0x08, 0x42, 0x2c, 0x00, 0x02, 0x03, 0x04, 0x05,
+               0x06, 0x08, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+               0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xd0, 0x02,
+               /* 0x00, 0x20, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, */
+               0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,
+               0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00,
+               0x40, 0x01, 0xa5, 0x55, 0xc0, 0xa8, 0x0a, 0x02,
+               0xc0, 0xa8, 0x0a, 0x01, 0x08, 0x00, 0x3a, 0xb0,
+               0x00, 0x00, 0x00, 0x00, 0xcd, 0x4c, 0x05, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x0a, 0x0b,
+               0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+               0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+               0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+               0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+               0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
+               0x34, 0x35, 0x36, 0x37,
+               /* 0x68, 0x81, 0xa3, 0xf3, 0xd6, 0x48, 0xd0, 0x3c */
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+
+       wpa_printf(MSG_INFO, "\nIEEE Std 802.11-2012, M.6.3 TKIP test "
+                  "vector\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "Plaintext MPDU", frame, sizeof(frame));
+
+       enc = tkip_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt TKIP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+
+       wpa_debug_level = MSG_INFO;
+       plain = tkip_decrypt(tk, (const struct ieee80211_hdr *) enc,
+                            enc + 24, enc_len - 24, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt TKIP frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 24 ||
+           os_memcmp(plain, frame + 24, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_ccmp(void)
+{
+       u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+                   0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f };
+       u8 pn[] = { 0xB5, 0x03, 0x97, 0x76, 0xE7, 0x0C };
+       u8 frame[] = {
+               0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
+               0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
+               0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
+               0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+               0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+               0x7e, 0x78, 0xa0, 0x50
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+       u8 fcs[4];
+
+       wpa_printf(MSG_INFO, "\nIEEE Std 802.11-2012, M.6.4 CCMP test "
+                  "vector\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "802.11 Header", frame, 24);
+       wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 24, sizeof(frame) - 24);
+
+       enc = ccmp_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs));
+
+       wpa_debug_level = MSG_INFO;
+       plain = ccmp_decrypt(tk, (const struct ieee80211_hdr *) enc,
+                            enc + 24, enc_len - 24, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt CCMP frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 24 ||
+           os_memcmp(plain, frame + 24, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_bip(void)
+{
+       u8 igtk[] = {
+               0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e,
+               0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf
+       };
+       u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       u8 frame[] = {
+               0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+               0x02, 0x00
+       };
+       u8 *prot;
+       size_t prot_len;
+
+       wpa_printf(MSG_INFO, "\nIEEE Std 802.11-2012, M.9.1 BIP with broadcast "
+                  "Deauthentication frame\n");
+
+       wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk));
+       wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn));
+       wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame));
+
+       prot = bip_protect(igtk, frame, sizeof(frame), ipn, 4, &prot_len);
+       if (prot == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to protect BIP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len);
+       os_free(prot);
+}
+
+
+static void test_vector_ccmp_mgmt(void)
+{
+       u8 tk[] = { 0x66, 0xed, 0x21, 0x04, 0x2f, 0x9f, 0x26, 0xd7,
+                   0x11, 0x57, 0x06, 0xe4, 0x04, 0x14, 0xcf, 0x2e };
+       u8 pn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+       u8 frame[] = {
+               0xc0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+               0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00,
+               0x02, 0x00
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+
+       wpa_printf(MSG_INFO, "\nIEEE Std 802.11-2012, M.9.2 CCMP with unicast "
+                  "Deauthentication frame\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "802.11 Header", frame, 24);
+       wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 24, sizeof(frame) - 24);
+
+       enc = ccmp_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+
+       wpa_debug_level = MSG_INFO;
+       plain = ccmp_decrypt(tk, (const struct ieee80211_hdr *) enc,
+                            enc + 24, enc_len - 24, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt CCMP frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 24 ||
+           os_memcmp(plain, frame + 24, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_gcmp(void)
+{
+       u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+                   0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f };
+       u8 pn[] = {
+               0x00, 0x89, 0x5F, 0x5F, 0x2B, 0x08
+       };
+       u8 frame[] = {
+               0x88, 0x48, 0x0b, 0x00, 0x0f, 0xd2, 0xe1, 0x28,
+               0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
+               0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 0x80, 0x33,
+               0x03, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+               0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+               0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+               0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+               0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+               0x26, 0x27
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+       u8 fcs[4];
+
+       wpa_printf(MSG_INFO, "\nIEEE P802.11ad/D9.0, M.11.1 GCMP test "
+                  "vector #2\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "802.11 Header", frame, 26);
+       wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 26, sizeof(frame) - 26);
+
+       enc = gcmp_encrypt(tk, sizeof(tk), frame, sizeof(frame), 26, frame + 24,
+                          pn, 0, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt GCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs));
+
+       wpa_debug_level = MSG_INFO;
+       plain = gcmp_decrypt(tk, sizeof(tk), (const struct ieee80211_hdr *) enc,
+                            enc + 26, enc_len - 26, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt GCMP frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 26 ||
+           os_memcmp(plain, frame + 26, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_gcmp_256(void)
+{
+       u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+                   0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f,
+                   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+       u8 pn[] = {
+               0x00, 0x89, 0x5F, 0x5F, 0x2B, 0x08
+       };
+       u8 frame[] = {
+               0x88, 0x48, 0x0b, 0x00, 0x0f, 0xd2, 0xe1, 0x28,
+               0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
+               0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 0x80, 0x33,
+               0x03, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+               0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+               0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+               0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+               0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+               0x26, 0x27
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+       u8 fcs[4];
+
+       wpa_printf(MSG_INFO, "\nGCMP-256 test vector\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "802.11 Header", frame, 26);
+       wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 26, sizeof(frame) - 26);
+
+       enc = gcmp_encrypt(tk, sizeof(tk), frame, sizeof(frame), 26, frame + 24,
+                          pn, 0, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt GCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs));
+
+       wpa_debug_level = MSG_INFO;
+       plain = gcmp_decrypt(tk, sizeof(tk), (const struct ieee80211_hdr *) enc,
+                            enc + 26, enc_len - 26, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt GCMP frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 26 ||
+           os_memcmp(plain, frame + 26, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_ccmp_256(void)
+{
+       u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+                   0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f,
+                   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+       u8 pn[] = { 0xB5, 0x03, 0x97, 0x76, 0xE7, 0x0C };
+       u8 frame[] = {
+               0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
+               0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
+               0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
+               0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+               0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+               0x7e, 0x78, 0xa0, 0x50
+       };
+       u8 *enc, *plain;
+       size_t enc_len, plain_len;
+       u8 fcs[4];
+
+       wpa_printf(MSG_INFO, "\nCCMP-256 test vector\n");
+
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn));
+       wpa_hexdump(MSG_INFO, "802.11 Header", frame, 24);
+       wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 24, sizeof(frame) - 24);
+
+       enc = ccmp_256_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0,
+                              &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs));
+
+       wpa_debug_level = MSG_INFO;
+       plain = ccmp_256_decrypt(tk, (const struct ieee80211_hdr *) enc,
+                                enc + 24, enc_len - 24, &plain_len);
+       wpa_debug_level = MSG_EXCESSIVE;
+       os_free(enc);
+
+       if (plain == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to decrypt CCMP-256 frame");
+               return;
+       }
+
+       if (plain_len != sizeof(frame) - 24 ||
+           os_memcmp(plain, frame + 24, plain_len) != 0) {
+               wpa_hexdump(MSG_ERROR, "Decryption result did not match",
+                           plain, plain_len);
+       }
+
+       os_free(plain);
+}
+
+
+static void test_vector_bip_gmac_128(void)
+{
+       u8 igtk[] = {
+               0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e,
+               0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf
+       };
+       u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       u8 frame[] = {
+               0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+               0x02, 0x00
+       };
+       u8 *prot;
+       size_t prot_len;
+
+       wpa_printf(MSG_INFO, "\nBIP-GMAC-128 with broadcast "
+                  "Deauthentication frame\n");
+
+       wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk));
+       wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn));
+       wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame));
+
+       prot = bip_gmac_protect(igtk, sizeof(igtk), frame, sizeof(frame),
+                               ipn, 4, &prot_len);
+       if (prot == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to protect BIP-GMAC-128 frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len);
+       os_free(prot);
+}
+
+
+static void test_vector_bip_gmac_256(void)
+{
+       u8 igtk[] = {
+               0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e,
+               0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf,
+               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+               0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+       };
+       u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       u8 frame[] = {
+               0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+               0x02, 0x00
+       };
+       u8 *prot;
+       size_t prot_len;
+
+       wpa_printf(MSG_INFO, "\nBIP-GMAC-256 with broadcast "
+                  "Deauthentication frame\n");
+
+       wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk));
+       wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn));
+       wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame));
+
+       prot = bip_gmac_protect(igtk, sizeof(igtk), frame, sizeof(frame),
+                               ipn, 4, &prot_len);
+       if (prot == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to protect BIP-GMAC-256 frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len);
+       os_free(prot);
+}
+
+
+int main(int argc, char *argv[])
+{
+       wpa_debug_level = MSG_EXCESSIVE;
+       wpa_debug_show_keys = 1;
+
+       if (os_program_init())
+               return -1;
+
+       test_vector_tkip();
+       test_vector_ccmp();
+       test_vector_bip();
+       test_vector_ccmp_mgmt();
+       test_vector_gcmp();
+       test_vector_gcmp_256();
+       test_vector_ccmp_256();
+       test_vector_bip_gmac_128();
+       test_vector_bip_gmac_256();
+
+       os_program_deinit();
+
+       return 0;
+}
index 3533914..ed3d601 100644 (file)
@@ -2,14 +2,8 @@
  * Temporal Key Integrity Protocol (CCMP)
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -382,6 +376,53 @@ void tkip_get_pn(u8 *pn, const u8 *data)
 u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
                  u8 *pn, int keyid, size_t *encrypted_len)
 {
-       /* TODO */
-       return NULL;
+       u8 michael_hdr[16];
+       u8 mic[8];
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       const u8 *mic_key;
+       u8 *crypt, *pos;
+       u16 iv16;
+       u32 iv32;
+       u16 ttak[5];
+       u8 rc4key[16];
+
+       if (len < sizeof(*hdr) || len < hdrlen)
+               return NULL;
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+
+       michael_mic_hdr(hdr, michael_hdr);
+       mic_key = tk + ((fc & WLAN_FC_FROMDS) ? 16 : 24);
+       michael_mic(mic_key, michael_hdr, frame + hdrlen, len - hdrlen, mic);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP: MIC", mic, sizeof(mic));
+
+       iv32 = WPA_GET_BE32(pn);
+       iv16 = WPA_GET_BE16(pn + 4);
+       tkip_mixing_phase1(ttak, tk, hdr->addr2, iv32);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP TTAK", (u8 *) ttak, sizeof(ttak));
+       tkip_mixing_phase2(rc4key, tk, ttak, iv16);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP RC4KEY", rc4key, sizeof(rc4key));
+
+       crypt = os_malloc(len + 8 + sizeof(mic) + 4);
+       if (crypt == NULL)
+               return NULL;
+       os_memcpy(crypt, frame, hdrlen);
+       pos = crypt + hdrlen;
+       os_memcpy(pos, rc4key, 3);
+       pos += 3;
+       *pos++ = keyid << 6 | BIT(5);
+       *pos++ = pn[3];
+       *pos++ = pn[2];
+       *pos++ = pn[1];
+       *pos++ = pn[0];
+
+       os_memcpy(pos, frame + hdrlen, len - hdrlen);
+       os_memcpy(pos + len - hdrlen, mic, sizeof(mic));
+       WPA_PUT_LE32(pos + len - hdrlen + sizeof(mic),
+                    crc32(pos, len - hdrlen + sizeof(mic)));
+       wep_crypt(rc4key, pos, len - hdrlen + sizeof(mic) + 4);
+
+       *encrypted_len = len + 8 + sizeof(mic) + 4;
+       return crypt;
 }
index 13ff218..c4137f3 100644 (file)
@@ -2,14 +2,8 @@
  * Wired Equivalent Privacy (WEP)
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index bf9f163..77a395f 100644 (file)
@@ -2,14 +2,8 @@
  * Received frame processing for wired interface
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index a1a0b04..5b691fa 100644 (file)
@@ -2,14 +2,8 @@
  * wlantest - IEEE 802.11 protocol monitoring and testing tool
  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -31,11 +25,12 @@ static void wlantest_terminate(int sig, void *signal_ctx)
 
 static void usage(void)
 {
-       printf("wlantest [-cddhqq] [-i<ifname>] [-r<pcap file>] "
+       printf("wlantest [-cddhqqF] [-i<ifname>] [-r<pcap file>] "
               "[-p<passphrase>]\n"
-               "         [-I<wired ifname>] [-R<wired pcap file>] "
+              "         [-I<wired ifname>] [-R<wired pcap file>] "
               "[-P<RADIUS shared secret>]\n"
-               "         [-w<write pcap file>] [-f<MSK/PMK file>]\n");
+              "         [-n<write pcapng file>]\n"
+              "         [-w<write pcap file>] [-f<MSK/PMK file>]\n");
 }
 
 
@@ -103,6 +98,10 @@ static void wlantest_deinit(struct wlantest *wt)
        dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list)
                os_free(wep);
        write_pcap_deinit(wt);
+       write_pcapng_deinit(wt);
+       clear_notes(wt);
+       os_free(wt->decrypted);
+       wt->decrypted = NULL;
 }
 
 
@@ -194,6 +193,58 @@ int add_wep(struct wlantest *wt, const char *key)
 }
 
 
+void add_note(struct wlantest *wt, int level, const char *fmt, ...)
+{
+       va_list ap;
+       size_t len = 1000;
+       int wlen;
+
+       if (wt->num_notes == MAX_NOTES)
+               return;
+
+       wt->notes[wt->num_notes] = os_malloc(len);
+       if (wt->notes[wt->num_notes] == NULL)
+               return;
+       va_start(ap, fmt);
+       wlen = vsnprintf(wt->notes[wt->num_notes], len, fmt, ap);
+       va_end(ap);
+       if (wlen < 0) {
+               os_free(wt->notes[wt->num_notes]);
+               wt->notes[wt->num_notes] = NULL;
+               return;
+       }
+       if (wlen >= len)
+               wt->notes[wt->num_notes][len - 1] = '\0';
+       wpa_printf(level, "%s", wt->notes[wt->num_notes]);
+       wt->num_notes++;
+}
+
+
+void clear_notes(struct wlantest *wt)
+{
+       size_t i;
+
+       for (i = 0; i < wt->num_notes; i++) {
+               os_free(wt->notes[i]);
+               wt->notes[i] = NULL;
+       }
+
+       wt->num_notes = 0;
+}
+
+
+size_t notes_len(struct wlantest *wt, size_t hdrlen)
+{
+       size_t i;
+       size_t len = wt->num_notes * hdrlen;
+
+       for (i = 0; i < wt->num_notes; i++)
+               len += os_strlen(wt->notes[i]);
+
+       return len;
+}
+
+
 int main(int argc, char *argv[])
 {
        int c;
@@ -202,6 +253,7 @@ int main(int argc, char *argv[])
        const char *write_file = NULL;
        const char *ifname = NULL;
        const char *ifname_wired = NULL;
+       const char *pcapng_file = NULL;
        struct wlantest wt;
        int ctrl_iface = 0;
 
@@ -214,7 +266,7 @@ int main(int argc, char *argv[])
        wlantest_init(&wt);
 
        for (;;) {
-               c = getopt(argc, argv, "cdf:hi:I:p:P:qr:R:w:W:");
+               c = getopt(argc, argv, "cdf:Fhi:I:n:p:P:qr:R:w:W:");
                if (c < 0)
                        break;
                switch (c) {
@@ -229,6 +281,9 @@ int main(int argc, char *argv[])
                        if (add_pmk_file(&wt, optarg) < 0)
                                return -1;
                        break;
+               case 'F':
+                       wt.assume_fcs = 1;
+                       break;
                case 'h':
                        usage();
                        return 0;
@@ -238,6 +293,9 @@ int main(int argc, char *argv[])
                case 'I':
                        ifname_wired = optarg;
                        break;
+               case 'n':
+                       pcapng_file = optarg;
+                       break;
                case 'p':
                        add_passphrase(&wt, optarg);
                        break;
@@ -278,6 +336,9 @@ int main(int argc, char *argv[])
        if (write_file && write_pcap_init(&wt, write_file) < 0)
                return -1;
 
+       if (pcapng_file && write_pcapng_init(&wt, pcapng_file) < 0)
+               return -1;
+
        if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
                return -1;
 
index 4c65d48..1ff3229 100644 (file)
@@ -2,14 +2,8 @@
  * wlantest - IEEE 802.11 protocol monitoring and testing tool
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WLANTEST_H
@@ -93,6 +87,10 @@ struct wlantest_sta {
 
        int pwrmgt;
        int pspoll;
+
+       u8 gtk[32];
+       size_t gtk_len;
+       int gtk_idx;
 };
 
 struct wlantest_tdls {
@@ -108,6 +106,8 @@ struct wlantest_tdls {
        u8 rsc_init[16 + 1][6];
        u8 rsc_resp[16 + 1][6];
        u32 counters[NUM_WLANTEST_TDLS_COUNTER];
+       u8 inonce[32];
+       u8 rnonce[32];
 };
 
 struct wlantest_bss {
@@ -150,6 +150,7 @@ struct wlantest_radius {
 
 
 #define MAX_CTRL_CONNECTIONS 10
+#define MAX_NOTES 10
 
 struct wlantest {
        int monitor_sock;
@@ -173,20 +174,44 @@ struct wlantest {
        void *write_pcap; /* pcap_t* */
        void *write_pcap_dumper; /* pcpa_dumper_t */
        struct timeval write_pcap_time;
+       u8 *decrypted;
+       size_t decrypted_len;
+       FILE *pcapng;
+       u32 write_pcapng_time_high;
+       u32 write_pcapng_time_low;
 
        u8 last_hdr[30];
        size_t last_len;
        int last_mgmt_valid;
+
+       unsigned int assume_fcs:1;
+
+       char *notes[MAX_NOTES];
+       size_t num_notes;
 };
 
+void add_note(struct wlantest *wt, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+void clear_notes(struct wlantest *wt);
+size_t notes_len(struct wlantest *wt, size_t hdrlen);
+
 int add_wep(struct wlantest *wt, const char *key);
 int read_cap_file(struct wlantest *wt, const char *fname);
 int read_wired_cap_file(struct wlantest *wt, const char *fname);
+
 int write_pcap_init(struct wlantest *wt, const char *fname);
 void write_pcap_deinit(struct wlantest *wt);
 void write_pcap_captured(struct wlantest *wt, const u8 *buf, size_t len);
 void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
                          const u8 *buf2, size_t len2);
+
+int write_pcapng_init(struct wlantest *wt, const char *fname);
+void write_pcapng_deinit(struct wlantest *wt);
+struct pcap_pkthdr;
+void write_pcapng_write_read(struct wlantest *wt, int dlt,
+                            struct pcap_pkthdr *hdr, const u8 *data);
+void write_pcapng_captured(struct wlantest *wt, const u8 *buf, size_t len);
+
 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len);
 void wlantest_process_prism(struct wlantest *wt, const u8 *data, size_t len);
 void wlantest_process_80211(struct wlantest *wt, const u8 *data, size_t len);
@@ -229,6 +254,10 @@ u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
 u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
                  u8 *pn, int keyid, size_t *encrypted_len);
 void ccmp_get_pn(u8 *pn, const u8 *data);
+u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
+                     const u8 *data, size_t data_len, size_t *decrypted_len);
+u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+                     u8 *qos, u8 *pn, int keyid, size_t *encrypted_len);
 
 u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                  const u8 *data, size_t data_len, size_t *decrypted_len);
@@ -239,6 +268,17 @@ void tkip_get_pn(u8 *pn, const u8 *data);
 u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr,
                 const u8 *data, size_t data_len, size_t *decrypted_len);
 
+u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid,
+                size_t *prot_len);
+u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
+                     u8 *ipn, int keyid, size_t *prot_len);
+
+u8 * gcmp_decrypt(const u8 *tk, size_t tk_len, const struct ieee80211_hdr *hdr,
+                 const u8 *data, size_t data_len, size_t *decrypted_len);
+u8 * gcmp_encrypt(const u8 *tk, size_t tk_len, u8 *frame, size_t len,
+                 size_t hdrlen, u8 *qos,
+                 u8 *pn, int keyid, size_t *encrypted_len);
+
 int ctrl_init(struct wlantest *wt);
 void ctrl_deinit(struct wlantest *wt);
 
index 6377fc1..a531b60 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wlantest controller
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -176,7 +170,7 @@ static char ** get_bssid_list(int s)
        if (bssid == NULL)
                return NULL;
 
-       res = os_zalloc((len / ETH_ALEN + 1) * sizeof(char *));
+       res = os_calloc(len / ETH_ALEN + 1, sizeof(char *));
        if (res == NULL)
                return NULL;
        for (i = 0; i < len / ETH_ALEN; i++) {
@@ -214,7 +208,7 @@ static char ** get_sta_list(int s, const u8 *bssid, int add_bcast)
        if (addr == NULL)
                return NULL;
 
-       res = os_zalloc((len / ETH_ALEN + 1 + add_bcast) * sizeof(char *));
+       res = os_calloc(len / ETH_ALEN + 1 + add_bcast, sizeof(char *));
        if (res == NULL)
                return NULL;
        for (i = 0; i < len / ETH_ALEN; i++) {
@@ -629,7 +623,7 @@ static char ** complete_get_sta_counter(int s, const char *str, int pos)
        case 1:
                /* counter list */
                count = sizeof(sta_counters) / sizeof(sta_counters[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        return NULL;
                for (i = 0; sta_counters[i].name; i++) {
@@ -728,7 +722,7 @@ static char ** complete_get_bss_counter(int s, const char *str, int pos)
        case 1:
                /* counter list */
                count = sizeof(bss_counters) / sizeof(bss_counters[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        return NULL;
                for (i = 0; bss_counters[i].name; i++) {
@@ -842,7 +836,7 @@ static char ** complete_get_tdls_counter(int s, const char *str, int pos)
        case 1:
                /* counter list */
                count = sizeof(tdls_counters) / sizeof(tdls_counters[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        return NULL;
                for (i = 0; tdls_counters[i].name; i++) {
@@ -978,7 +972,7 @@ static char ** complete_inject(int s, const char *str, int pos)
        case 1:
                /* frame list */
                count = sizeof(inject_frames) / sizeof(inject_frames[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        break;
                for (i = 0; inject_frames[i].name; i++) {
@@ -988,7 +982,7 @@ static char ** complete_inject(int s, const char *str, int pos)
                }
                break;
        case 2:
-               res = os_zalloc(5 * sizeof(char *));
+               res = os_calloc(5, sizeof(char *));
                if (res == NULL)
                        break;
                res[0] = os_strdup("normal");
@@ -1005,7 +999,7 @@ static char ** complete_inject(int s, const char *str, int pos)
                        break;
                break;
        case 3:
-               res = os_zalloc(3 * sizeof(char *));
+               res = os_calloc(3, sizeof(char *));
                if (res == NULL)
                        break;
                res[0] = os_strdup("ap");
@@ -1128,7 +1122,7 @@ static char ** complete_send(int s, const char *str, int pos)
 
        switch (arg) {
        case 1:
-               res = os_zalloc(5 * sizeof(char *));
+               res = os_calloc(5, sizeof(char *));
                if (res == NULL)
                        break;
                res[0] = os_strdup("normal");
@@ -1215,6 +1209,30 @@ static int cmd_add_passphrase(int s, int argc, char *argv[])
 }
 
 
+static int cmd_add_wepkey(int s, int argc, char *argv[])
+{
+       u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
+       u8 buf[100], *pos, *end;
+       int rlen;
+
+       if (argc < 1) {
+               printf("add_wepkey needs one argument: WEP key\n");
+               return -1;
+       }
+
+       pos = buf;
+       end = buf + sizeof(buf);
+       WPA_PUT_BE32(pos, WLANTEST_CTRL_ADD_PASSPHRASE);
+       pos += 4;
+       pos = attr_add_str(pos, end, WLANTEST_ATTR_WEPKEY, argv[0]);
+
+       rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
+       if (rlen < 0)
+               return -1;
+       return 0;
+}
+
+
 struct sta_infos {
        const char *name;
        enum wlantest_sta_info num;
@@ -1226,6 +1244,7 @@ static const struct sta_infos sta_infos[] = {
        { "key_mgmt", WLANTEST_STA_INFO_KEY_MGMT },
        { "rsn_capab", WLANTEST_STA_INFO_RSN_CAPAB },
        { "state", WLANTEST_STA_INFO_STATE },
+       { "gtk", WLANTEST_STA_INFO_GTK },
        { NULL, 0 }
 };
 
@@ -1304,7 +1323,7 @@ static char ** complete_info_sta(int s, const char *str, int pos)
        case 1:
                /* counter list */
                count = sizeof(sta_infos) / sizeof(sta_infos[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        return NULL;
                for (i = 0; sta_infos[i].name; i++) {
@@ -1409,7 +1428,7 @@ static char ** complete_info_bss(int s, const char *str, int pos)
        case 1:
                /* counter list */
                count = sizeof(bss_infos) / sizeof(bss_infos[0]);
-               res = os_zalloc(count * sizeof(char *));
+               res = os_calloc(count, sizeof(char *));
                if (res == NULL)
                        return NULL;
                for (i = 0; bss_infos[i].name; i++) {
@@ -1460,6 +1479,8 @@ static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
        { "version", cmd_version, "= get wlantest version", NULL },
        { "add_passphrase", cmd_add_passphrase,
          "<passphrase> = add a known passphrase", NULL },
+       { "add_wepkey", cmd_add_wepkey,
+         "<WEP key> = add a known WEP key", NULL },
        { "info_sta", cmd_info_sta,
          "<field> <BSSID> <STA> = get STA information",
          complete_info_sta },
@@ -1589,7 +1610,7 @@ static char ** wlantest_cli_cmd_list(void)
 
        count = sizeof(wlantest_cli_commands) /
                sizeof(wlantest_cli_commands[0]);
-       res = os_zalloc(count * sizeof(char *));
+       res = os_calloc(count, sizeof(char *));
        if (res == NULL)
                return NULL;
 
@@ -1668,7 +1689,7 @@ static void wlantest_cli_interactive(int s)
        cli.s = s;
        eloop_register_signal_terminate(wlantest_cli_eloop_terminate, &cli);
        edit_init(wlantest_cli_edit_cmd_cb, wlantest_cli_edit_eof_cb,
-                 wlantest_cli_edit_completion_cb, &cli, hfile);
+                 wlantest_cli_edit_completion_cb, &cli, hfile, NULL);
 
        eloop_run();
 
index 9731bd6..618cf8c 100644 (file)
@@ -2,14 +2,8 @@
  * wlantest control interface
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WLANTEST_CTRL_H
@@ -157,6 +151,7 @@ enum wlantest_sta_info {
        WLANTEST_STA_INFO_KEY_MGMT,
        WLANTEST_STA_INFO_RSN_CAPAB,
        WLANTEST_STA_INFO_STATE,
+       WLANTEST_STA_INFO_GTK,
 };
 
 enum wlantest_bss_info {
index b59a1c2..58f01a0 100644 (file)
@@ -2,14 +2,8 @@
  * PCAP capture file writer
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -80,15 +74,15 @@ void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
        u8 *buf;
        size_t len;
 
-       if (!wt->write_pcap_dumper)
+       if (!wt->write_pcap_dumper && !wt->pcapng)
                return;
 
-       os_memset(&h, 0, sizeof(h));
-       h.ts = wt->write_pcap_time;
+       os_free(wt->decrypted);
        len = sizeof(rtap) + len1 + len2;
-       buf = os_malloc(len);
+       wt->decrypted = buf = os_malloc(len);
        if (buf == NULL)
                return;
+       wt->decrypted_len = len;
        os_memcpy(buf, rtap, sizeof(rtap));
        if (buf1) {
                os_memcpy(buf + sizeof(rtap), buf1, len1);
@@ -96,8 +90,267 @@ void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
        }
        if (buf2)
                os_memcpy(buf + sizeof(rtap) + len1, buf2, len2);
+
+       if (!wt->write_pcap_dumper)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       h.ts = wt->write_pcap_time;
        h.caplen = len;
        h.len = len;
        pcap_dump(wt->write_pcap_dumper, &h, buf);
-       os_free(buf);
+}
+
+
+struct pcapng_section_header {
+       u32 block_type; /* 0x0a0d0d0a */
+       u32 block_total_len;
+       u32 byte_order_magic;
+       u16 major_version;
+       u16 minor_version;
+       u64 section_len;
+       u32 block_total_len2;
+} STRUCT_PACKED;
+
+struct pcapng_interface_description {
+       u32 block_type; /* 0x00000001 */
+       u32 block_total_len;
+       u16 link_type;
+       u16 reserved;
+       u32 snap_len;
+       u32 block_total_len2;
+} STRUCT_PACKED;
+
+struct pcapng_enhanced_packet {
+       u32 block_type; /* 0x00000006 */
+       u32 block_total_len;
+       u32 interface_id;
+       u32 timestamp_high;
+       u32 timestamp_low;
+       u32 captured_len;
+       u32 packet_len;
+       /* Packet data - aligned to 32 bits */
+       /* Options (variable) */
+       /* Block Total Length copy */
+} STRUCT_PACKED;
+
+#define PCAPNG_BYTE_ORDER_MAGIC 0x1a2b3c4d
+#define PCAPNG_BLOCK_IFACE_DESC 0x00000001
+#define PCAPNG_BLOCK_PACKET 0x00000002
+#define PCAPNG_BLOCK_SIMPLE_PACKET 0x00000003
+#define PCAPNG_BLOCK_NAME_RESOLUTION 0x00000004
+#define PCAPNG_BLOCK_INTERFACE_STATISTICS 0x00000005
+#define PCAPNG_BLOCK_ENHANCED_PACKET 0x00000006
+#define PCAPNG_BLOCK_SECTION_HEADER 0x0a0d0d0a
+
+#define LINKTYPE_IEEE802_11 105
+#define LINKTYPE_IEEE802_11_RADIO 127
+
+#define PAD32(a) ((4 - ((a) & 3)) & 3)
+#define ALIGN32(a) ((a) + PAD32((a)))
+
+
+int write_pcapng_init(struct wlantest *wt, const char *fname)
+{
+       struct pcapng_section_header hdr;
+       struct pcapng_interface_description desc;
+
+       wt->pcapng = fopen(fname, "wb");
+       if (wt->pcapng == NULL)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "Writing PCAPNG dump to '%s'", fname);
+
+       os_memset(&hdr, 0, sizeof(hdr));
+       hdr.block_type = PCAPNG_BLOCK_SECTION_HEADER;
+       hdr.block_total_len = sizeof(hdr);
+       hdr.byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC;
+       hdr.major_version = 1;
+       hdr.minor_version = 0;
+       hdr.section_len = -1;
+       hdr.block_total_len2 = hdr.block_total_len;
+       fwrite(&hdr, sizeof(hdr), 1, wt->pcapng);
+
+       os_memset(&desc, 0, sizeof(desc));
+       desc.block_type = PCAPNG_BLOCK_IFACE_DESC;
+       desc.block_total_len = sizeof(desc);
+       desc.block_total_len2 = desc.block_total_len;
+       desc.link_type = LINKTYPE_IEEE802_11_RADIO;
+       desc.snap_len = 65535;
+       fwrite(&desc, sizeof(desc), 1, wt->pcapng);
+
+       return 0;
+}
+
+
+void write_pcapng_deinit(struct wlantest *wt)
+{
+       if (wt->pcapng) {
+               fclose(wt->pcapng);
+               wt->pcapng = NULL;
+       }
+}
+
+
+static u8 * pcapng_add_comments(struct wlantest *wt, u8 *pos)
+{
+       size_t i;
+       u16 *len;
+
+       if (!wt->num_notes)
+               return pos;
+
+       *((u16 *) pos) = 1 /* opt_comment */;
+       pos += 2;
+       len = (u16 *) pos /* length to be filled in */;
+       pos += 2;
+
+       for (i = 0; i < wt->num_notes; i++) {
+               size_t nlen = os_strlen(wt->notes[i]);
+               if (i > 0)
+                       *pos++ = '\n';
+               os_memcpy(pos, wt->notes[i], nlen);
+               pos += nlen;
+       }
+       *len = pos - (u8 *) len - 2;
+       pos += PAD32(*len);
+
+       *((u16 *) pos) = 0 /* opt_endofopt */;
+       pos += 2;
+       *((u16 *) pos) = 0;
+       pos += 2;
+
+       return pos;
+}
+
+
+static void write_pcapng_decrypted(struct wlantest *wt)
+{
+       size_t len;
+       struct pcapng_enhanced_packet *pkt;
+       u8 *pos;
+       u32 *block_len;
+
+       if (!wt->pcapng || wt->decrypted == NULL)
+               return;
+
+       add_note(wt, MSG_EXCESSIVE, "decrypted version of the previous frame");
+
+       len = sizeof(*pkt) + wt->decrypted_len + 100 + notes_len(wt, 32);
+       pkt = os_zalloc(len);
+       if (pkt == NULL)
+               return;
+
+       pkt->block_type = PCAPNG_BLOCK_ENHANCED_PACKET;
+       pkt->interface_id = 0;
+       pkt->timestamp_high = wt->write_pcapng_time_high;
+       pkt->timestamp_low = wt->write_pcapng_time_low;
+       pkt->captured_len = wt->decrypted_len;
+       pkt->packet_len = wt->decrypted_len;
+
+       pos = (u8 *) (pkt + 1);
+
+       os_memcpy(pos, wt->decrypted, wt->decrypted_len);
+       pos += ALIGN32(wt->decrypted_len);
+
+       pos = pcapng_add_comments(wt, pos);
+
+       block_len = (u32 *) pos;
+       pos += 4;
+       *block_len = pkt->block_total_len = pos - (u8 *) pkt;
+
+       fwrite(pkt, pos - (u8 *) pkt, 1, wt->pcapng);
+
+       os_free(pkt);
+}
+
+
+void write_pcapng_write_read(struct wlantest *wt, int dlt,
+                            struct pcap_pkthdr *hdr, const u8 *data)
+{
+       struct pcapng_enhanced_packet *pkt;
+       u8 *pos;
+       u32 *block_len;
+       u64 timestamp;
+       size_t len, datalen = hdr->caplen;
+       u8 rtap[] = {
+               0x00 /* rev */,
+               0x00 /* pad */,
+               0x0a, 0x00, /* header len */
+               0x02, 0x00, 0x00, 0x00, /* present flags */
+               0x00, /* flags */
+               0x00 /* pad */
+       };
+
+       if (wt->assume_fcs)
+               rtap[8] |= 0x10;
+
+       if (!wt->pcapng)
+               return;
+
+       len = sizeof(*pkt) + hdr->len + 100 + notes_len(wt, 32) + sizeof(rtap);
+       pkt = os_zalloc(len);
+       if (pkt == NULL)
+               return;
+
+       pkt->block_type = PCAPNG_BLOCK_ENHANCED_PACKET;
+       pkt->interface_id = 0;
+       timestamp = 1000000 * hdr->ts.tv_sec + hdr->ts.tv_usec;
+       pkt->timestamp_high = timestamp >> 32;
+       pkt->timestamp_low = timestamp & 0xffffffff;
+       wt->write_pcapng_time_high = pkt->timestamp_high;
+       wt->write_pcapng_time_low = pkt->timestamp_low;
+       pkt->captured_len = hdr->caplen;
+       pkt->packet_len = hdr->len;
+
+       pos = (u8 *) (pkt + 1);
+
+       switch (dlt) {
+       case DLT_IEEE802_11_RADIO:
+               break;
+       case DLT_PRISM_HEADER:
+               /* remove prism header (could be kept ... lazy) */
+               pkt->captured_len -= WPA_GET_LE32(data + 4);
+               pkt->packet_len -= WPA_GET_LE32(data + 4);
+               datalen -= WPA_GET_LE32(data + 4);
+               data += WPA_GET_LE32(data + 4);
+               /* fall through */
+       case DLT_IEEE802_11:
+               pkt->captured_len += sizeof(rtap);
+               pkt->packet_len += sizeof(rtap);
+               os_memcpy(pos, &rtap, sizeof(rtap));
+               pos += sizeof(rtap);
+               break;
+       default:
+               return;
+       }
+
+       os_memcpy(pos, data, datalen);
+       pos += datalen + PAD32(pkt->captured_len);
+       pos = pcapng_add_comments(wt, pos);
+
+       block_len = (u32 *) pos;
+       pos += 4;
+       *block_len = pkt->block_total_len = pos - (u8 *) pkt;
+
+       fwrite(pkt, pos - (u8 *) pkt, 1, wt->pcapng);
+
+       os_free(pkt);
+
+       write_pcapng_decrypted(wt);
+}
+
+
+void write_pcapng_captured(struct wlantest *wt, const u8 *buf, size_t len)
+{
+       struct pcap_pkthdr h;
+
+       if (!wt->pcapng)
+               return;
+
+       os_memset(&h, 0, sizeof(h));
+       gettimeofday(&h.ts, NULL);
+       h.caplen = len;
+       h.len = len;
+       write_pcapng_write_read(wt, DLT_IEEE802_11_RADIO, &h, buf);
 }
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
new file mode 100644 (file)
index 0000000..0e3ad1b
--- /dev/null
@@ -0,0 +1 @@
+*.service
index a656239..6b6fc06 100644 (file)
@@ -1,18 +1,8 @@
 #
 # Copyright (C) 2008 The Android Open Source Project
 #
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
 #
 
 LOCAL_PATH := $(call my-dir)
@@ -26,14 +16,21 @@ endif
 
 ifeq ($(WPA_BUILD_SUPPLICANT),true)
 
-include $(LOCAL_PATH)/.config
+include $(LOCAL_PATH)/android.config
 
 # To ignore possible wrong network configurations
 L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
 
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
 # Set Android log name
 L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\"
 
+# Disable roaming in wpa_supplicant
+ifdef CONFIG_NO_ROAMING
+L_CFLAGS += -DCONFIG_NO_ROAMING
+endif
+
 # Use Android specific directory for control interface sockets
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
 L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\"
@@ -66,11 +63,19 @@ INCLUDES += $(LOCAL_PATH)/src/tls
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += $(LOCAL_PATH)/src/wps
 INCLUDES += external/openssl/include
+# frameworks/base/cmds/keystore is the old location and can be dropped at some
+# point
 INCLUDES += frameworks/base/cmds/keystore
+INCLUDES += system/security/keystore
 ifdef CONFIG_DRIVER_NL80211
 INCLUDES += external/libnl-headers
 endif
 
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
 OBJS = config.c
 OBJS += notify.c
 OBJS += bss.c
@@ -125,11 +130,22 @@ endif
 OBJS += src/utils/$(CONFIG_ELOOP).c
 OBJS_c += src/utils/$(CONFIG_ELOOP).c
 
+ifdef CONFIG_ELOOP_POLL
+L_CFLAGS += -DCONFIG_ELOOP_POLL
+endif
 
 ifdef CONFIG_EAPOL_TEST
 L_CFLAGS += -Werror -DEAPOL_TEST
 endif
 
+ifdef CONFIG_HT_OVERRIDES
+L_CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifdef CONFIG_VHT_OVERRIDES
+L_CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
 ifndef CONFIG_BACKEND
 CONFIG_BACKEND=file
 endif
@@ -176,6 +192,18 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.c
+endif
+
 ifdef CONFIG_TDLS
 L_CFLAGS += -DCONFIG_TDLS
 OBJS += src/rsn_supp/tdls.c
@@ -203,7 +231,7 @@ NEED_SHA1=y
 NEED_MD5=y
 NEED_RC4=y
 else
-L_CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+L_CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -236,16 +264,23 @@ L_CFLAGS += -DCONFIG_P2P_STRICT
 endif
 endif
 
+ifdef CONFIG_WIFI_DISPLAY
+L_CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.c
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.c
+L_CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
 ifdef CONFIG_INTERWORKING
 OBJS += interworking.c
 L_CFLAGS += -DCONFIG_INTERWORKING
 NEED_GAS=y
 endif
 
-ifdef CONFIG_NO_WPA2
-L_CFLAGS += -DCONFIG_NO_WPA2
-endif
-
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
 ifdef CONFIG_AP
@@ -534,7 +569,7 @@ endif
 ifdef CONFIG_EAP_PWD
 L_CFLAGS += -DEAP_PWD
 OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
-OBJS_h += src/eap_server/eap_pwd.c
+OBJS_h += src/eap_server/eap_server_pwd.c
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
@@ -566,25 +601,10 @@ NEED_80211_COMMON=y
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 L_CFLAGS += -DCONFIG_WPS_NFC
 OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -710,12 +730,16 @@ OBJS += src/ap/ieee802_11_shared.c
 OBJS += src/ap/drv_callbacks.c
 OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
+OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 endif
 ifdef CONFIG_CTRL_IFACE
 OBJS += src/ap/ctrl_iface_ap.c
 endif
+ifdef CONFIG_WNM
+OBJS += src/ap/wnm_ap.c
+endif
 
 L_CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
 OBJS += src/eap_server/eap_server.c
@@ -738,6 +762,12 @@ L_CFLAGS += -DEAP_SERVER_WSC
 OBJS += src/ap/wps_hostapd.c
 OBJS += src/eap_server/eap_server_wsc.c
 endif
+ifdef CONFIG_INTERWORKING
+OBJS += src/ap/gas_serv.c
+endif
+ifdef CONFIG_HS20
+OBJS += src/ap/hs20.c
+endif
 endif
 
 ifdef NEED_RSN_AUTHENTICATOR
@@ -836,7 +866,11 @@ NEED_DES=y
 # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
 OBJS += src/eap_peer/eap_tls_common.c
 OBJS_h += src/eap_server/eap_server_tls_common.c
+ifndef CONFIG_FIPS
 NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
+endif
 endif
 
 ifndef CONFIG_TLS
@@ -847,6 +881,11 @@ ifdef CONFIG_TLSV11
 L_CFLAGS += -DCONFIG_TLSV11
 endif
 
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 L_CFLAGS += -DEAP_TLS_OPENSSL
@@ -931,6 +970,9 @@ OBJS += src/tls/pkcs8.c
 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
 L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1036,8 +1078,12 @@ AESOBJS += src/crypto/aes-encblock.c
 endif
 ifdef NEED_AES_OMAC1
 NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
 AESOBJS += src/crypto/aes-omac1.c
 endif
+endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
 AESOBJS += src/crypto/aes-wrap.c
@@ -1057,7 +1103,10 @@ endif
 
 SHA1OBJS =
 ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
 SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += src/crypto/sha1-internal.c
 ifdef NEED_FIPS186_2_PRF
@@ -1067,8 +1116,10 @@ endif
 ifdef CONFIG_NO_WPA_PASSPHRASE
 L_CFLAGS += -DCONFIG_NO_PBKDF2
 else
+ifneq ($(CONFIG_TLS), openssl)
 SHA1OBJS += src/crypto/sha1-pbkdf2.c
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += src/crypto/sha1-tprf.c
 endif
@@ -1077,14 +1128,13 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c
 endif
 endif
 
-MD5OBJS = src/crypto/md5.c
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += src/crypto/md5-internal.c
 endif
-ifdef CONFIG_FIPS
-MD5OBJS += src/crypto/md5-non-fips.c
-endif
 OBJS += $(MD5OBJS)
 OBJS_p += $(MD5OBJS)
 endif
@@ -1111,10 +1161,16 @@ endif
 SHA256OBJS = # none by default
 ifdef NEED_SHA256
 L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
 SHA256OBJS += src/crypto/sha256.c
+endif
+SHA256OBJS += src/crypto/sha256-prf.c
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += src/crypto/sha256-internal.c
 endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += src/crypto/sha256-tlsprf.c
+endif
 OBJS += $(SHA256OBJS)
 endif
 
@@ -1130,6 +1186,10 @@ OBJS += src/crypto/dh_group5.c
 endif
 endif
 
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
 ifdef CONFIG_NO_RANDOM_POOL
 L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
@@ -1154,6 +1214,11 @@ endif
 ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
 L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
 endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
 OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
 endif
 
@@ -1171,17 +1236,6 @@ 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
 
@@ -1285,6 +1339,10 @@ L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
 endif
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 L_CFLAGS += -DCONFIG_DEBUG_FILE
 endif
@@ -1300,6 +1358,7 @@ endif
 OBJS += $(SHA1OBJS) $(DESOBJS)
 
 OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
 
 ifdef CONFIG_BGSCAN_SIMPLE
 L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1318,8 +1377,36 @@ L_CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.c
 endif
 
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
 ifdef NEED_GAS
-OBJS += ../src/common/gas.c
+OBJS += src/common/gas.c
 OBJS += gas_query.c
 L_CFLAGS += -DCONFIG_GAS
 NEED_OFFCHANNEL=y
@@ -1357,6 +1444,9 @@ OBJS_priv += src/utils/common.c
 OBJS_priv += src/utils/wpa_debug.c
 OBJS_priv += src/utils/wpabuf.c
 OBJS_priv += wpa_priv.c
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += src/common/ieee802_11_common.c
+endif
 ifdef CONFIG_DRIVER_TEST
 OBJS_priv += $(SHA1OBJS)
 OBJS_priv += $(MD5OBJS)
@@ -1421,6 +1511,12 @@ ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
 LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
 endif
 LOCAL_SHARED_LIBRARIES := libc libcutils
+
+ifdef CONFIG_EAP_PROXY
+OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 LOCAL_SHARED_LIBRARIES += libcrypto libssl
 endif
index 06119c6..3f10e11 100644 (file)
@@ -1,5 +1,413 @@
 ChangeLog for wpa_supplicant
 
+????-??-?? - v2.1
+       * added support for simulataneous authentication of equals (SAE) for
+         stronger password-based authentication with WPA2-Personal
+
+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
index cab9dfd..10e14cc 100644 (file)
@@ -6,21 +6,24 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
-export LIBDIR ?= /usr/lib
-export BINDIR ?= /usr/sbin
+export LIBDIR ?= /usr/local/lib/
+export BINDIR ?= /usr/local/sbin/
 PKG_CONFIG ?= pkg-config
 
 CFLAGS += -I../src
 CFLAGS += -I../src/utils
+CFLAGS += -fPIE
+LDFLAGS += -pie
 
 -include .config
 
-ALL=wpa_supplicant wpa_cli
+BINALL=wpa_supplicant wpa_cli
 
 ifndef CONFIG_NO_WPA_PASSPHRASE
-ALL += wpa_passphrase
+BINALL += wpa_passphrase
 endif
 
+ALL = $(BINALL)
 ALL += systemd/wpa_supplicant.service
 ALL += systemd/wpa_supplicant@.service
 ALL += systemd/wpa_supplicant-nl80211@.service
@@ -48,11 +51,17 @@ mkconfig:
        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
+$(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
@@ -70,6 +79,10 @@ OBJS_c += ../src/utils/common.o
 
 
 CFLAGS += -DTIZEN_EXT
+CFLAGS += -DTIZEN_EXT_P2P
+CFLAGS += -DTIZEN_EXT_ENROLLEE
+CFLAGS += -DTIZEN_EXT_BUSY_DEVICE
+CFLAGS += -DBCM_DRIVER_V115
 
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
@@ -109,11 +122,23 @@ 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
+
+ifdef CONFIG_VHT_OVERRIDES
+CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
 ifndef CONFIG_BACKEND
 CONFIG_BACKEND=file
 endif
@@ -160,6 +185,18 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.o
+endif
+
 ifdef CONFIG_TDLS
 CFLAGS += -DCONFIG_TDLS
 OBJS += ../src/rsn_supp/tdls.o
@@ -187,7 +224,7 @@ NEED_SHA1=y
 NEED_MD5=y
 NEED_RC4=y
 else
-CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -220,16 +257,23 @@ 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)
@@ -283,6 +327,17 @@ 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)
@@ -436,6 +491,13 @@ CONFIG_EAP_SIM_COMMON=y
 NEED_AES_CBC=y
 endif
 
+ifdef CONFIG_EAP_PROXY
+CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
 ifdef CONFIG_EAP_AKA_PRIME
 # EAP-AKA'
 ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
@@ -517,7 +579,7 @@ 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
+OBJS_h += ../src/eap_server/eap_server_pwd.o
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
@@ -549,25 +611,10 @@ 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
@@ -693,9 +740,13 @@ 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
@@ -721,6 +772,12 @@ 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
@@ -819,7 +876,11 @@ 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
@@ -848,6 +909,10 @@ 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)
@@ -1027,8 +1092,12 @@ 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
@@ -1047,7 +1116,10 @@ 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
@@ -1057,8 +1129,10 @@ 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
@@ -1067,14 +1141,13 @@ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
 endif
 endif
 
-MD5OBJS = ../src/crypto/md5.o
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
 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
@@ -1101,7 +1174,10 @@ 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
@@ -1123,6 +1199,10 @@ OBJS += ../src/crypto/dh_group5.o
 endif
 endif
 
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
 ifdef CONFIG_NO_RANDOM_POOL
 CFLAGS += -DCONFIG_NO_RANDOM_POOL
 else
@@ -1147,6 +1227,11 @@ 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
 
@@ -1164,17 +1249,6 @@ 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
 
@@ -1274,6 +1348,10 @@ 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
@@ -1284,6 +1362,9 @@ endif
 
 ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
 endif
 
 OBJS += $(SHA1OBJS) $(DESOBJS)
@@ -1308,6 +1389,34 @@ 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
@@ -1321,6 +1430,7 @@ CFLAGS += -DCONFIG_OFFCHANNEL
 endif
 
 OBJS += ../src/drivers/driver_common.o
+OBJS_priv += ../src/drivers/driver_common.o
 
 OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
 OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
@@ -1336,6 +1446,10 @@ 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
@@ -1444,6 +1558,10 @@ 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 " $@
@@ -1479,6 +1597,9 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_com
 %.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
@@ -1518,10 +1639,16 @@ test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
 
 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)
index 4d02f8f..78df89e 100644 (file)
@@ -1,37 +1,22 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2013, Jouni Malinen <j@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 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
 -------
 
-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:
+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
@@ -130,13 +115,15 @@ Current hardware/software requirements:
 - 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
+       Linux drivers that support cfg80211/nl80211. 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.
+       note that Linux drivers are moving to use generic wireless configuration
+       interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line)
+       should be the default option to start with before falling back to driver
+       specific interface.
+
+       Linux drivers that support WPA/WPA2 configuration with the generic
+       Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211.
 
        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
@@ -423,6 +410,7 @@ Command line options
 
 usage:
   wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+        [-G<group>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
         [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
         [-p<driver_param>] [-b<br_ifname>] ...]
@@ -437,10 +425,11 @@ options:
   -D = driver name (can be multiple drivers: nl80211,wext)
   -f = Log output to default log location (normally /tmp)
   -g = global ctrl_interface
+  -G = global ctrl_interface group
   -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)
+  -L = show license (BSD)
   -p = driver parameters
   -P = PID file
   -q = decrease debugging verbosity (-qq even less)
@@ -451,6 +440,7 @@ options:
   -N = start describing new interface
 
 drivers:
+  nl80211 = Linux nl80211/cfg80211
   wext = Linux wireless extensions (generic)
   wired = wpa_supplicant wired Ethernet driver
   roboswitch = wpa_supplicant Broadcom switch driver
@@ -492,7 +482,7 @@ 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
+wpa_supplicant -cw.conf -Dnl80211 -iwlan0 -bbr0
 
 
 Configuration file
@@ -884,10 +874,10 @@ 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
+# Add a new interface (wlan0, no configuration file, driver=nl80211, and
 # enable control interface)
 wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
-       "" wext /var/run/wpa_supplicant
+       "" nl80211 /var/run/wpa_supplicant
 
 # Configure a network using the newly added network interface:
 wpa_cli -iwlan0 add_network
@@ -948,7 +938,7 @@ Example configuration:
   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
+  wpa_priv -B -P /var/run/wpa_priv.pid nl80211:wlan0
 - run wpa_supplicant as non-root with a user that is in wpapriv group:
   wpa_supplicant -i ath0 -c wpa_supplicant.conf
 
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
new file mode 100644 (file)
index 0000000..5669c55
--- /dev/null
@@ -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@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
index db6e4ae..8447a90 100644 (file)
@@ -71,7 +71,8 @@ over the main control interface.
 
 Device Discovery
 
-p2p_find [timeout in seconds] [type=<social|progressive>]
+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
@@ -81,6 +82,11 @@ 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
@@ -101,7 +107,7 @@ Flush P2P peer table and state.
 
 Group Formation
 
-p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
+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
@@ -112,10 +118,14 @@ 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.
+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] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
+       [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,
@@ -128,7 +138,12 @@ 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.
+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
@@ -146,7 +161,12 @@ Negotiation.
 "freq" can be used to set a forced operating channel (e.g., freq=2412
 to select 2.4 GHz channel 1).
 
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+"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
@@ -171,7 +191,13 @@ group interface is used as a parameter for this command.
 
 p2p_cancel
 
-Cancel an ongoing P2P group formation related operation.
+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
 
@@ -199,6 +225,19 @@ This command returns an identifier for the pending query (e.g.,
 will be automatically removed when the specified peer has replied to
 it.
 
+Service Query TLV has following format:
+Length (2 octets, little endian) - length of following data
+Service Protocol Type (1 octet) - see the table below
+Service Transaction ID (1 octet) - nonzero identifier for the TLV
+Query Data (Length - 2 octets of data) - service protocol specific data
+
+Service Protocol Types:
+0 = All service protocols
+1 = Bonjour
+2 = UPnP
+3 = WS-Discovery
+4 = Wi-Fi Display
+
 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):
@@ -236,6 +275,14 @@ p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:Content
 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
@@ -318,15 +365,20 @@ Remove all local services from internal SD query processing.
 Invitation
 
 p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
-       [go_dev_addr=address]
+       [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
 
 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 persisten group, the peer parameter is not needed. Otherwise it is
+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).
+cases). When reinvoking a persistent group, the GO device can specify
+the frequency for the group with the freq parameter. When reinvoking a
+persistent group, the P2P client device can use freq parameter to force
+a specific operating channel (or invitation failure if GO rejects that)
+or pref parameter to request a specific channel (while allowing GO to
+select to use another channel, if needed).
 
 Group Operations
 
index bf75cb4..3d07109 100644 (file)
@@ -67,6 +67,10 @@ 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
@@ -126,6 +130,12 @@ 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.
@@ -249,16 +259,16 @@ wps_er_start [IP address]
 wps_er_stop
 - stop WPS ER functionality
 
-wps_er_learn <UUID> <AP PIN>
+wps_er_learn <UUID|BSSID> <AP PIN>
 - learn AP configuration
 
-wps_er_set_config <UUID> <network id>
+wps_er_set_config <UUID|BSSID> <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>
+wps_er_config <UUID|BSSID> <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 ""
@@ -267,10 +277,10 @@ wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
 <encr> must be one of the following: NONE WEP TKIP CCMP
 
 
-wps_er_pbc <Enrollee UUID>
+wps_er_pbc <Enrollee UUID|MAC address>
 - accept an Enrollee PBC using External Registrar
 
-wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+wps_er_pin <Enrollee UUID|"any"|MAC address> <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
@@ -303,3 +313,99 @@ 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).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token when wpa_supplicant is controlling an AP
+interface (AP or P2P GO). 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.
+
+The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used
+to build an NFC configuration token based on a locally configured
+network.
+
+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> [UUID|BSSID]" 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). If the options
+UUID|BSSID argument is included, this is a request to build the handover
+message for the specified AP when wpa_supplicant is operating as a WPS
+ER.
+
+"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.
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" can be used as an alternative way for
+reporting completed NFC connection handover. The first parameter
+indicates whether the local device initiated or responded to the
+connection handover and the carrier records are the selected carrier
+from the handover request and select messages as a hexdump.
+
+The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be
+used to build an NFC configuration token for the specified AP when
+wpa_supplicant is operating as a WPS ER. The output value from this
+command is a hexdump of the selected 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.
index 292223d..7288abd 100644 (file)
@@ -4,13 +4,8 @@ wpa_supplicant for Windows
 Copyright (c) 2003-2009, Jouni Malinen <j@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@cryptsoft.com).
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
 
 
 wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
@@ -35,20 +30,6 @@ authentication and successfully ping a wired host):
 - 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
 ----------------------------------
 
@@ -316,135 +297,3 @@ HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
 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@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@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@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@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@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@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
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
new file mode 100644 (file)
index 0000000..6686422
--- /dev/null
@@ -0,0 +1,533 @@
+# 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
+CONFIG_LIBNL20=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
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_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 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
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+CONFIG_ANDROID_LOG=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
+
+# Disable roaming in wpa_supplicant
+CONFIG_NO_ROAMING=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
+
+CONFIG_TDLS=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
+
+include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
index a3b460e..bf84dc4 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2003-2009, Jouni Malinen <j@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -52,7 +46,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                                  struct hostapd_config *conf)
 {
        struct hostapd_bss_config *bss = &conf->bss[0];
-       int pairwise;
 
        conf->driver = wpa_s->driver;
 
@@ -62,17 +55,14 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                /* 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;
+               conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+                                                      &conf->channel);
+               if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+                       wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: "
+                                  "%d MHz", ssid->frequency);
+                       return -1;
+               }
        }
 
        /* TODO: enable HT40 if driver supports it;
@@ -87,15 +77,36 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
         */
        if (wpa_s->hw.modes) {
                struct hostapd_hw_modes *mode = NULL;
-               int i;
+               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;
                        }
                }
-               if (mode && mode->ht_capab) {
+
+#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
@@ -113,7 +124,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
-       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+           (ssid->mode == WPAS_MODE_P2P_GO ||
+            ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
                /* Remove 802.11b rates from supported and basic rate sets */
                int *list = os_malloc(4 * sizeof(int));
                if (list) {
@@ -147,10 +160,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                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;
 
+       bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
+
        if (ssid->auth_alg)
                bss->auth_algs = ssid->auth_alg;
 
@@ -158,15 +172,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                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) {
+       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;
@@ -185,19 +199,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                wep->keys_set = 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 (ssid->ap_max_inactivity)
+               bss->ap_max_inactivity = ssid->ap_max_inactivity;
+
+       if (ssid->dtim_period)
+               bss->dtim_period = ssid->dtim_period;
+       else if (wpa_s->conf->dtim_period)
+               bss->dtim_period = wpa_s->conf->dtim_period;
+
+       if (ssid->beacon_int)
+               conf->beacon_int = ssid->beacon_int;
+       else if (wpa_s->conf->beacon_int)
+               conf->beacon_int = wpa_s->conf->beacon_int;
+
+       if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+               bss->rsn_pairwise = bss->wpa_pairwise;
+       bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+                                                   bss->rsn_pairwise);
 
        if (bss->wpa && bss->ieee802_1x)
                bss->ssid.security_policy = SECURITY_WPA;
@@ -228,6 +246,16 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                bss->rsn_pairwise = WPA_CIPHER_NONE;
        }
 
+       if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+           (bss->wpa_group == WPA_CIPHER_CCMP ||
+            bss->wpa_group == WPA_CIPHER_GCMP)) {
+               /*
+                * Strong ciphers do not need frequent rekeying, so increase
+                * the default GTK rekeying period to 24 hours.
+                */
+               bss->wpa_group_rekey = 86400;
+       }
+
 #ifdef CONFIG_WPS
        /*
         * Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -239,12 +267,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                goto no_wps;
 #ifdef CONFIG_WPS2
        if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
-           (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+           (!(bss->rsn_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;
-       bss->wps_state = 2;
+
+       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);
@@ -267,6 +298,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        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 */
 
@@ -278,6 +310,11 @@ no_wps:
 
        bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
 
+       if (wpa_s->conf->ap_vendor_elements) {
+               bss->vendor_elements =
+                       wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+       }
+
        return 0;
 }
 
@@ -328,9 +365,9 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event,
 
 
 static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
-                                int authorized)
+                                int authorized, const u8 *p2p_dev_addr)
 {
-       wpas_notify_sta_authorized(ctx, mac_addr, authorized);
+       wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
 }
 
 
@@ -355,11 +392,13 @@ static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 
 
 static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
-                          const u8 *bssid, const u8 *ie, size_t ie_len)
+                          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);
+       return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+                                    ssi_signal);
 #else /* CONFIG_P2P */
        return 0;
 #endif /* CONFIG_P2P */
@@ -431,18 +470,15 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                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_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
+                                                         1);
+       if (wpa_s->pairwise_cipher < 0) {
                wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
                           "cipher.");
                return -1;
        }
-       params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+       params.pairwise_suite =
+               wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
        params.group_suite = params.pairwise_suite;
 
 #ifdef CONFIG_P2P
@@ -467,6 +503,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        hapd_iface->owner = wpa_s;
        hapd_iface->drv_flags = wpa_s->drv_flags;
        hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+       hapd_iface->extended_capa = wpa_s->extended_capa;
+       hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+       hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
 
        wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
        if (conf == NULL) {
@@ -474,6 +513,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *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;
@@ -494,7 +537,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_P2P */
 
        hapd_iface->num_bss = conf->num_bss;
-       hapd_iface->bss = os_zalloc(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);
@@ -526,9 +569,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                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->p2p_persistent_group,
-                       ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+               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;
@@ -563,7 +605,6 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
 
        wpa_s->current_ssid = NULL;
        wpa_s->assoc_freq = 0;
-       wpa_s->reassociated_connection = 0;
 #ifdef CONFIG_P2P
        if (wpa_s->ap_iface->bss)
                wpa_s->ap_iface->bss[0]->p2p_group = NULL;
@@ -657,21 +698,6 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-static int wpa_supplicant_ap_wps_sta_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;
-}
-
-
 int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 {
        struct wps_registrar *reg;
@@ -683,7 +709,7 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
        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],
-                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+                                 ap_sta_wps_cancel, NULL);
 
        if (!reg_sel && !wps_sta) {
                wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
@@ -703,7 +729,8 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 
 
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                             const char *pin, char *buf, size_t buflen)
+                             const char *pin, char *buf, size_t buflen,
+                             int timeout)
 {
        int ret, ret_len = 0;
 
@@ -718,7 +745,7 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                ret_len = os_snprintf(buf, buflen, "%s", pin);
 
        ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
-                                 0);
+                                 timeout);
        if (ret)
                return -1;
        return ret_len;
@@ -841,6 +868,34 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
        hapd->conf->ap_pin = NULL;
 }
 
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                            int ndef)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
 #endif /* CONFIG_WPS */
 
 
@@ -876,6 +931,26 @@ int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
 }
 
 
+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)
 {
@@ -913,7 +988,9 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
        struct wpa_ssid *ssid = wpa_s->current_ssid;
        struct hostapd_data *hapd;
 
-       if (ssid == NULL || wpa_s->ap_iface == NULL)
+       if (ssid == NULL || wpa_s->ap_iface == NULL ||
+           ssid->mode == WPAS_MODE_INFRA ||
+           ssid->mode == WPAS_MODE_IBSS)
                return -1;
 
 #ifdef CONFIG_P2P
@@ -924,14 +1001,27 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
                        P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
-       ieee802_11_set_beacons(iface);
        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)
 {
index aa4c362..fd4c25a 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2003-2009, Jouni Malinen <j@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef AP_H
@@ -24,7 +18,8 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
 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);
+                             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);
@@ -37,6 +32,10 @@ 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,
@@ -51,5 +50,11 @@ 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);
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef);
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                            int ndef);
 
 #endif /* AP_H */
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
new file mode 100644 (file)
index 0000000..a2cf7a5
--- /dev/null
@@ -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;
+}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
new file mode 100644 (file)
index 0000000..e2a7652
--- /dev/null
@@ -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 */
diff --git a/wpa_supplicant/autoscan_exponential.c b/wpa_supplicant/autoscan_exponential.c
new file mode 100644 (file)
index 0000000..424477b
--- /dev/null
@@ -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,
+};
diff --git a/wpa_supplicant/autoscan_periodic.c b/wpa_supplicant/autoscan_periodic.c
new file mode 100644 (file)
index 0000000..102d723
--- /dev/null
@@ -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,
+};
index 5661830..9a9bd52 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - background scan and roaming interface
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index ae94a48..e9d15fc 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - background scan and roaming interface
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BGSCAN_H
index 5385cce..07d31e4 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - background scan and roaming module: learn
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -81,7 +75,7 @@ static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
        if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
                return;
 
-       n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+       n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
        if (n == NULL)
                return;
 
@@ -225,7 +219,7 @@ static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
        dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
                if (in_array(freqs, bss->freq))
                        continue;
-               n = os_realloc(freqs, (*count + 2) * sizeof(int));
+               n = os_realloc_array(freqs, *count + 2, sizeof(int));
                if (n == NULL)
                        return freqs;
                freqs = n;
@@ -248,13 +242,16 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
 
        idx = data->probe_idx + 1;
        while (idx != data->probe_idx) {
-               if (data->supp_freqs[idx] == 0)
+               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(freqs, (count + 2) * sizeof(int));
+                       n = os_realloc_array(freqs, count + 2, sizeof(int));
                        if (n == NULL)
                                return freqs;
                        freqs = n;
@@ -366,7 +363,7 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
                for (j = 0; j < modes[i].num_channels; j++) {
                        if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
                                continue;
-                       n = os_realloc(freqs, (count + 2) * sizeof(int));
+                       n = os_realloc_array(freqs, count + 2, sizeof(int));
                        if (n == NULL)
                                continue;
 
index eedc961..479f703 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - background scan and roaming module: simple
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -29,6 +23,7 @@ struct bgscan_simple_data {
        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;
@@ -66,12 +61,19 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
                         * scanning at the short scan interval. After that,
                         * revert to the long scan interval.
                         */
-                       if (data->short_scan_count >
-                           data->long_interval / data->short_interval + 1) {
+                       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);
        }
@@ -138,6 +140,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
        }
 
        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;
@@ -222,9 +225,15 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
                wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
                           "bgscan interval");
                data->scan_interval = data->short_interval;
-               data->short_scan_count = 0;
                os_get_time(&now);
-               if (now.sec > data->last_bgscan.sec + 1)
+               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) {
index 8f12ac9..e53dc38 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Temporary BSSID blacklist
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -29,6 +23,9 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
 {
        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)
@@ -60,6 +57,9 @@ 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++;
@@ -93,6 +93,9 @@ 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) {
@@ -120,14 +123,19 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
 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;
 }
index de280cd..ae06986 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Temporary BSSID blacklist
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BLACKLIST_H
index dec9323..0e1576b 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #define WPA_BSS_IES_CHANGED_FLAG       BIT(8)
 
 
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+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'", bss->id, MAC2STR(bss->bssid),
-               wpa_ssid_txt(bss->ssid, bss->ssid_len));
+               " 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);
-#ifdef CONFIG_INTERWORKING
-       wpabuf_free(bss->anqp_venue_name);
-       wpabuf_free(bss->anqp_network_auth_type);
-       wpabuf_free(bss->anqp_roaming_consortium);
-       wpabuf_free(bss->anqp_ip_addr_type_availability);
-       wpabuf_free(bss->anqp_nai_realm);
-       wpabuf_free(bss->anqp_3gpp);
-       wpabuf_free(bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
+       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 &&
@@ -77,10 +224,27 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+static void calculate_update_time(const struct os_time *fetch_time,
+                                 unsigned int age_ms,
+                                 struct os_time *update_time)
 {
        os_time_t usec;
 
+       update_time->sec = fetch_time->sec;
+       update_time->usec = fetch_time->usec;
+       update_time->sec -= age_ms / 1000;
+       usec = (age_ms % 1000) * 1000;
+       if (update_time->usec < usec) {
+               update_time->sec--;
+               update_time->usec += 1000000;
+       }
+       update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+                            struct os_time *fetch_time)
+{
        dst->flags = src->flags;
        os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
        dst->freq = src->freq;
@@ -91,14 +255,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
        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;
+       calculate_update_time(fetch_time, src->age, &dst->last_update);
 }
 
 
@@ -118,13 +275,21 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *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;
+}
+
+
 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);
+                       wpa_bss_remove(wpa_s, bss, __func__);
                        return 0;
                }
        }
@@ -133,41 +298,50 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+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;
+               return 0;
 
        /*
-        * Remove the oldest entry since no better candidate for removal was
-        * found.
+        * Remove the oldest entry that isn't currently in use.
         */
-       wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
-                                           struct wpa_bss, list));
+       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 void wpa_bss_add(struct wpa_supplicant *wpa_s,
-                       const u8 *ssid, size_t ssid_len,
-                       struct wpa_scan_res *res)
+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 os_time *fetch_time)
 {
        struct wpa_bss *bss;
 
        bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
        if (bss == NULL)
-               return;
+               return NULL;
        bss->id = wpa_s->bss_next_id++;
        bss->last_update_idx = wpa_s->bss_update_idx;
-       wpa_bss_copy_res(bss, res);
+       wpa_bss_copy_res(bss, res, fetch_time);
        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);
@@ -176,8 +350,14 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
                " 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);
+       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;
 }
 
 
@@ -309,15 +489,16 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
 }
 
 
-static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-                          struct wpa_scan_res *res)
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+              struct wpa_scan_res *res, struct os_time *fetch_time)
 {
        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);
+       wpa_bss_copy_res(bss, res, fetch_time);
        /* Move the entry to the end of the list */
        dl_list_del(&bss->list);
        if (bss->ie_len + bss->beacon_ie_len >=
@@ -332,6 +513,15 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                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);
@@ -340,34 +530,66 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                }
                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);
-}
-
 
-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;
+       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
+ * @fetch_time: Time when the result was fetched from the driver
+ *
+ * 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)
+                            struct wpa_scan_res *res,
+                            struct os_time *fetch_time)
 {
        const u8 *ssid, *p2p;
        struct wpa_bss *bss;
 
+       if (wpa_s->conf->ignore_old_scan_res) {
+               struct os_time update;
+               calculate_update_time(fetch_time, res->age, &update);
+               if (os_time_before(&update, &wpa_s->scan_trigger_time)) {
+                       struct os_time age;
+                       os_time_sub(&wpa_s->scan_trigger_time, &update, &age);
+                       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
+                               "table entry that is %u.%06u seconds older "
+                               "than our scan trigger",
+                               (unsigned int) age.sec,
+                               (unsigned int) age.usec);
+                       return;
+               }
+       }
+
        ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
        if (ssid == NULL) {
                wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
@@ -381,6 +603,18 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
        }
 
        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 */
@@ -389,40 +623,30 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
         * (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);
+               bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
        else
-               wpa_bss_update(wpa_s, bss, res);
-}
-
+               bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
 
-/*
- * August 1st, 2011 TIZEN
- * This part is changed to reduce associating duration.
- */
-#if defined TIZEN_EXT
-struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s,
-               const u8 *ssid)
-{
-       struct wpa_bss *bss = NULL;
-       struct wpa_bss *compare = NULL;
-       dl_list_for_each(compare, &wpa_s->bss, struct wpa_bss, list) {
-               wpa_printf(MSG_DEBUG, "==================================================");
-               wpa_printf(MSG_DEBUG, "buffer's ssid '%s', request ssid '%s' ", compare->ssid, ssid);
-               wpa_printf(MSG_DEBUG, "==================================================");
-               if (os_strcmp(compare->ssid, ssid) == 0) {
-                       if (bss == NULL)
-                               bss = compare;
-                       if (compare->level > bss->level) {
-                               wpa_printf(MSG_DEBUG, "current signal level %d finded signal level %d",
-                                               bss->level, compare->level);
-                               bss = compare;
-                       }
-               }
+       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;
        }
 
-       return bss;
+       wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
 }
-#endif
+
 
 static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
                                    const struct scan_info *info)
@@ -465,14 +689,41 @@ static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
 }
 
 
+/**
+ * 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;
@@ -482,14 +733,24 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
                        bss->scan_miss_count++;
                if (bss->scan_miss_count >=
                    wpa_s->conf->bss_expiration_scan_count) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
-                               "no match in scan", bss->id);
-                       wpa_bss_remove(wpa_s, bss);
+                       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;
@@ -506,9 +767,7 @@ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
                        continue;
 
                if (os_time_before(&bss->last_update, &t)) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
-                               "age", bss->id);
-                       wpa_bss_remove(wpa_s, bss);
+                       wpa_bss_remove(wpa_s, bss, __func__);
                } else
                        break;
        }
@@ -525,6 +784,14 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+/**
+ * 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);
@@ -535,6 +802,10 @@ int wpa_bss_init(struct wpa_supplicant *wpa_s)
 }
 
 
+/**
+ * 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;
@@ -545,11 +816,15 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s)
        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);
+               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);
@@ -557,10 +832,18 @@ void wpa_bss_deinit(struct wpa_supplicant *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;
@@ -569,6 +852,63 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
 }
 
 
+/**
+ * wpa_bss_get_bssid_latest - Fetch the latest 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
+ *
+ * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
+ * find the entry that has the most recent update. This can help in finding the
+ * correct entry in cases where the SSID of the AP may have changed recently
+ * (e.g., in WPS reconfiguration cases).
+ */
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+                                         const u8 *bssid)
+{
+       struct wpa_bss *bss, *found = NULL;
+       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)
+                       continue;
+               if (found == NULL ||
+                   os_time_before(&found->last_update, &bss->last_update))
+                       found = bss;
+       }
+       return found;
+}
+
+
+#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;
@@ -580,6 +920,38 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
 }
 
 
+/**
+ * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @idf: Smallest allowed identifier assigned for the entry
+ * @idf: Largest allowed identifier assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
+ * smallest id value to be fetched within the specified range without the
+ * caller having to know the exact id.
+ */
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+                                     unsigned int idf, unsigned int idl)
+{
+       struct wpa_bss *bss;
+       dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+               if (bss->id >= idf && bss->id <= idl)
+                       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;
@@ -599,6 +971,15 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
 }
 
 
+/**
+ * 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;
@@ -619,6 +1000,16 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
 }
 
 
+/**
+ * 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)
 {
@@ -650,6 +1041,56 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
 }
 
 
+/**
+ * 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;
@@ -672,6 +1113,15 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss)
 }
 
 
+/**
+ * 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;
index 5dd8972..2b41948 100644 (file)
@@ -2,14 +2,8 @@
  * BSS table
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BSS_H
@@ -26,56 +20,76 @@ struct wpa_scan_res;
 #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
- * @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 {
+       /** 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;
-#ifdef CONFIG_INTERWORKING
-       struct wpabuf *anqp_venue_name;
-       struct wpabuf *anqp_network_auth_type;
-       struct wpabuf *anqp_roaming_consortium;
-       struct wpabuf *anqp_ip_addr_type_availability;
-       struct wpabuf *anqp_nai_realm;
-       struct wpabuf *anqp_3gpp;
-       struct wpabuf *anqp_domain_name;
-#endif /* CONFIG_INTERWORKING */
+       /** 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 */
@@ -83,18 +97,10 @@ struct wpa_bss {
 
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
-                            struct wpa_scan_res *res);
+                            struct wpa_scan_res *res,
+                            struct os_time *fetch_time);
 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
                        int new_scan);
-
-/*
- * August 1st, 2011 TIZEN
- * This part is changed to reduce associating duration.
- */
-#if defined TIZEN_EXT
-struct wpa_bss * wpa_bss_check_scan_res(struct wpa_supplicant *wpa_s, const u8 *ssid);
-#endif
-
 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);
@@ -103,12 +109,22 @@ 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_bssid_latest(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);
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+                                     unsigned int idf, unsigned int idl);
 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
 const u8 * wpa_bss_get_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 */
index b446a3f..a35be51 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -19,6 +13,7 @@
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
+#include "p2p/p2p.h"
 #include "config.h"
 
 
@@ -58,42 +53,6 @@ struct parse_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)
@@ -154,18 +113,6 @@ set:
 
 
 #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;
@@ -231,10 +178,17 @@ static int wpa_config_parse_int(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
 {
-       int *dst;
+       int val, *dst;
+       char *end;
 
        dst = (int *) (((u8 *) ssid) + (long) data->param1);
-       *dst = atoi(value);
+       val = strtol(value, &end, 0);
+       if (*end) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+                          line, value);
+               return -1;
+       }
+       *dst = val;
        wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
        if (data->param3 && *dst < (long) data->param3) {
@@ -329,6 +283,21 @@ 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;
@@ -353,11 +322,9 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                        return 0;
                ssid->psk_set = 0;
                os_free(ssid->passphrase);
-               ssid->passphrase = os_malloc(len + 1);
+               ssid->passphrase = dup_binstr(value, len);
                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 "
@@ -386,6 +353,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
 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,
@@ -531,6 +509,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                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);
@@ -650,47 +634,12 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
 
 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)
+       int val = wpa_parse_cipher(value);
+       if (val < 0) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+                          line, value);
                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);
@@ -703,62 +652,13 @@ static int wpa_config_parse_cipher(int line, const char *value)
 #ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_cipher(int cipher)
 {
-       char *buf, *pos, *end;
-       int ret;
-
-       pos = buf = os_zalloc(50);
+       char *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;
+       if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
+               os_free(buf);
+               return NULL;
        }
 
        return buf;
@@ -774,7 +674,7 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
        val = wpa_config_parse_cipher(line, value);
        if (val == -1)
                return -1;
-       if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+       if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -803,8 +703,7 @@ static int wpa_config_parse_group(const struct parse_data *data,
        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)) {
+       if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -924,9 +823,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
-static int * wpa_config_parse_freqs(const struct parse_data *data,
-                                   struct wpa_ssid *ssid, int line,
-                                   const char *value)
+static int * wpa_config_parse_int_array(const char *value)
 {
        int *freqs;
        size_t used, len;
@@ -934,7 +831,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
 
        used = 0;
        len = 10;
-       freqs = os_zalloc((len + 1) * sizeof(int));
+       freqs = os_calloc(len + 1, sizeof(int));
        if (freqs == NULL)
                return NULL;
 
@@ -945,7 +842,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
                if (used == len) {
                        int *n;
                        size_t i;
-                       n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
+                       n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
                        if (n == NULL) {
                                os_free(freqs);
                                return NULL;
@@ -973,7 +870,7 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
        os_free(ssid->scan_freq);
@@ -989,7 +886,7 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
        os_free(ssid->freq_list);
@@ -1074,8 +971,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
                last = *end == '\0';
                *end = '\0';
                tmp = methods;
-               methods = os_realloc(methods,
-                                    (num_methods + 1) * sizeof(*methods));
+               methods = os_realloc_array(methods, num_methods + 1,
+                                          sizeof(*methods));
                if (methods == NULL) {
                        os_free(tmp);
                        os_free(buf);
@@ -1105,7 +1002,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
        os_free(buf);
 
        tmp = methods;
-       methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
+       methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
        if (methods == NULL) {
                os_free(tmp);
                return -1;
@@ -1116,6 +1013,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
 
        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;
 }
@@ -1170,6 +1068,20 @@ static int wpa_config_parse_password(const struct parse_data *data,
                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;
@@ -1187,6 +1099,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
                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;
        }
@@ -1215,6 +1128,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
        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;
 }
@@ -1228,6 +1142,17 @@ static char * wpa_config_write_password(const struct parse_data *data,
        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);
@@ -1263,6 +1188,11 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
                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);
@@ -1351,6 +1281,99 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
 #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
@@ -1445,6 +1468,7 @@ static const struct parse_data ssid_fields[] = {
        { FUNC_KEY(psk) },
        { FUNC(proto) },
        { FUNC(key_mgmt) },
+       { INT(bg_scan_period) },
        { FUNC(pairwise) },
        { FUNC(group) },
        { FUNC(auth_alg) },
@@ -1498,6 +1522,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(eap_workaround) },
        { STRe(pac_file) },
        { INTe(fragment_size) },
+       { INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
        { INT_RANGE(mode, 0, 4) },
        { INT_RANGE(proactive_key_caching, 0, 1) },
@@ -1508,9 +1533,46 @@ static const struct parse_data ssid_fields[] = {
 #endif /* CONFIG_IEEE80211W */
        { INT_RANGE(peerkey, 0, 1) },
        { INT_RANGE(mixed_cell, 0, 1) },
-       { INT_RANGE(frequency, 0, 10000) },
+       { 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 */
+#ifdef CONFIG_VHT_OVERRIDES
+       { INT_RANGE(disable_vht, 0, 1) },
+       { INT(vht_capa) },
+       { INT(vht_capa_mask) },
+       { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
+#endif /* CONFIG_VHT_OVERRIDES */
+       { INT(ap_max_inactivity) },
+       { INT(dtim_period) },
+       { INT(beacon_int) },
 };
 
 #undef OFFSET
@@ -1564,19 +1626,20 @@ int wpa_config_add_prio_network(struct wpa_config *config,
        }
 
        /* First network for this priority - add a new priority list */
-       nlist = os_realloc(config->pssid,
-                          (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+       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)
+               if (nlist[prio]->priority < ssid->priority) {
+                       os_memmove(&nlist[prio + 1], &nlist[prio],
+                                  (config->num_prio - prio) *
+                                  sizeof(struct wpa_ssid *));
                        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;
@@ -1670,6 +1733,7 @@ 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 */
@@ -1677,10 +1741,34 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
        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()
@@ -1694,6 +1782,7 @@ void wpa_config_free(struct wpa_config *config)
        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) {
@@ -1702,6 +1791,13 @@ void wpa_config_free(struct wpa_config *config)
                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;
@@ -1712,11 +1808,14 @@ void wpa_config_free(struct wpa_config *config)
        }
 #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);
@@ -1726,12 +1825,15 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->config_methods);
        os_free(config->p2p_ssid_postfix);
        os_free(config->pssid);
-       os_free(config->home_realm);
-       os_free(config->home_username);
-       os_free(config->home_password);
-       os_free(config->home_ca_cert);
-       os_free(config->home_imsi);
-       os_free(config->home_milenage);
+       os_free(config->p2p_pref_chan);
+       os_free(config->autoscan);
+       os_free(config->freq_list);
+       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->sae_groups);
+       wpabuf_free(config->ap_vendor_elements);
        os_free(config);
 }
 
@@ -1859,11 +1961,42 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
        ssid->pairwise_cipher = DEFAULT_PAIRWISE;
        ssid->group_cipher = DEFAULT_GROUP;
        ssid->key_mgmt = DEFAULT_KEY_MGMT;
+       ssid->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 */
+#ifdef CONFIG_VHT_OVERRIDES
+       ssid->vht_rx_mcs_nss_1 = -1;
+       ssid->vht_rx_mcs_nss_2 = -1;
+       ssid->vht_rx_mcs_nss_3 = -1;
+       ssid->vht_rx_mcs_nss_4 = -1;
+       ssid->vht_rx_mcs_nss_5 = -1;
+       ssid->vht_rx_mcs_nss_6 = -1;
+       ssid->vht_rx_mcs_nss_7 = -1;
+       ssid->vht_rx_mcs_nss_8 = -1;
+       ssid->vht_tx_mcs_nss_1 = -1;
+       ssid->vht_tx_mcs_nss_2 = -1;
+       ssid->vht_tx_mcs_nss_3 = -1;
+       ssid->vht_tx_mcs_nss_4 = -1;
+       ssid->vht_tx_mcs_nss_5 = -1;
+       ssid->vht_tx_mcs_nss_6 = -1;
+       ssid->vht_tx_mcs_nss_7 = -1;
+       ssid->vht_tx_mcs_nss_8 = -1;
+#endif /* CONFIG_VHT_OVERRIDES */
+       ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+       ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -1958,7 +2091,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
 
        get_keys = get_keys && ssid->export_keys;
 
-       props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
+       props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
        if (!props)
                return NULL;
 
@@ -2086,8 +2219,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
 void wpa_config_update_psk(struct wpa_ssid *ssid)
 {
 #ifndef CONFIG_NO_PBKDF2
-       pbkdf2_sha1(ssid->passphrase,
-                   (char *) ssid->ssid, ssid->ssid_len, 4096,
+       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);
@@ -2096,6 +2228,248 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
 }
 
 
+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
@@ -2187,6 +2561,15 @@ 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)
@@ -2196,11 +2579,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        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->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+       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);
@@ -2249,9 +2638,18 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
                                       struct wpa_config *config, int line,
                                       const char *pos)
 {
-       int *dst;
+       int val, *dst;
+       char *end;
+
        dst = (int *) (((u8 *) config) + (long) data->param1);
-       *dst = atoi(pos);
+       val = strtol(pos, &end, 0);
+       if (*end) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+                          line, pos);
+               return -1;
+       }
+       *dst = val;
+
        wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
 
        if (data->param2 && *dst < (long) data->param2) {
@@ -2309,6 +2707,50 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
 }
 
 
+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_freq_list(const struct global_parse_data *data,
+                                       struct wpa_config *config, int line,
+                                       const char *value)
+{
+       int *freqs;
+
+       freqs = wpa_config_parse_int_array(value);
+       if (freqs == NULL)
+               return -1;
+       os_free(config->freq_list);
+       config->freq_list = freqs;
+       return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
                                      struct wpa_config *config, int line,
                                      const char *pos)
@@ -2383,6 +2825,43 @@ static int wpa_config_process_os_version(const struct global_parse_data *data,
        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
@@ -2406,6 +2885,56 @@ static int wpa_config_process_sec_device_type(
        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 */
 
 
@@ -2423,6 +2952,61 @@ static int wpa_config_process_hessid(
 }
 
 
+static int wpa_config_process_sae_groups(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       int *groups = wpa_config_parse_int_array(pos);
+       if (groups == NULL) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+                          line, pos);
+               return -1;
+       }
+
+       os_free(config->sae_groups);
+       config->sae_groups = groups;
+
+       return 0;
+}
+
+
+static int wpa_config_process_ap_vendor_elements(
+       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 ap_vendor_elements",
+                          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 "
+                                  "ap_vendor_elements", line);
+                       wpabuf_free(tmp);
+                       return -1;
+               }
+
+               wpabuf_free(config->ap_vendor_elements);
+               config->ap_vendor_elements = tmp;
+       } else {
+               wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+                          "ap_vendor_elements");
+               return -1;
+       }
+
+       return 0;
+}
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -2437,6 +3021,7 @@ static int wpa_config_process_hessid(
 #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
@@ -2445,10 +3030,13 @@ static const struct global_parse_data global_fields[] = {
 #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 },
@@ -2468,6 +3056,7 @@ static const struct global_parse_data global_fields[] = {
        { 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 },
@@ -2480,23 +3069,46 @@ static const struct global_parse_data global_fields[] = {
        { 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 },
+       { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 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 },
-       { STR(home_realm), 0 },
-       { STR(home_username), 0 },
-       { STR(home_password), 0 },
-       { STR(home_ca_cert), 0 },
-       { STR(home_imsi), 0 },
-       { STR(home_milenage), 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(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),
+         CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { 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 },
+       { FUNC(sae_groups), 0 },
+       { INT(dtim_period), 0 },
+       { INT(beacon_int), 0 },
+       { FUNC(ap_vendor_elements), 0 },
+       { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+       { FUNC(freq_list), 0 },
+       { INT(scan_cur_freq), 0 },
+       { INT(sched_scan_interval), 0 },
 };
 
 #undef FUNC
@@ -2506,6 +3118,7 @@ static const struct global_parse_data global_fields[] = {
 #undef _STR
 #undef STR
 #undef STR_RANGE
+#undef BIN
 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
 
 
@@ -2526,10 +3139,31 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
                                   "parse '%s'.", line, pos);
                        ret = -1;
                }
+               if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+                       config->wps_nfc_pw_from_config = 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'.",
index f9e5043..1748cf3 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CONFIG_H
 #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
+#define DEFAULT_SCAN_CUR_FREQ 0
 
 #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_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)
+#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
@@ -78,6 +253,13 @@ struct wpa_config {
        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
@@ -119,6 +301,15 @@ struct wpa_config {
        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
@@ -217,6 +408,23 @@ struct wpa_config {
        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
@@ -362,6 +570,11 @@ struct wpa_config {
        char *p2p_ssid_postfix;
        int persistent_reconnect;
        int p2p_intra_bss;
+       unsigned int num_p2p_pref_chan;
+       struct p2p_channel *p2p_pref_chan;
+       int p2p_ignore_shared_freq;
+
+       struct wpabuf *wps_vendor_ext_m1;
 
 #define MAX_WPS_VENDOR_EXT 10
        /**
@@ -380,9 +593,12 @@ struct wpa_config {
         * 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.
+        * 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.
         */
-       unsigned int p2p_group_idle;
+       int p2p_group_idle;
 
        /**
         * bss_max_count - Maximum number of BSS entries to keep in memory
@@ -417,11 +633,35 @@ struct wpa_config {
        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;
 
        /**
+        * freq_list - Array of allowed scan frequencies or %NULL for all
+        *
+        * This is an optional zero-terminated array of frequencies in
+        * megahertz (MHz) to allow for narrowing scanning range.
+        */
+       int *freq_list;
+
+       /**
+        * scan_cur_freq - Whether to scan only the current channel
+        *
+        * If true, attempt to scan only the current channel if any other
+        * VIFs on this radio are already associated on a particular channel.
+        */
+       int scan_cur_freq;
+
+       /**
         * changed_parameters - Bitmap of changed parameters since last update
         */
        unsigned int changed_parameters;
@@ -455,35 +695,187 @@ struct wpa_config {
        u8 hessid[ETH_ALEN];
 
        /**
-        * home_realm - Home Realm for Interworking
+        * hs20 - Hotspot 2.0
         */
-       char *home_realm;
+       int hs20;
 
        /**
-        * home_username - Username for Interworking network selection
+        * 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).
         */
-       char *home_username;
+       int pbc_in_m1;
 
        /**
-        * home_password - Password for Interworking network selection
+        * 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 *home_password;
+       char *autoscan;
 
        /**
-        * home_ca_cert - CA certificate for Interworking network selection
+        * wps_nfc_pw_from_config - NFC Device Password was read from config
+        *
+        * This parameter can be determined whether the NFC Device Password was
+        * included in the configuration (1) or generated dynamically (0). Only
+        * the former case is re-written back to the configuration file.
         */
-       char *home_ca_cert;
+       int wps_nfc_pw_from_config;
 
        /**
-        * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+        * wps_nfc_dev_pw_id - NFC Device Password ID for password token
         */
-       char *home_imsi;
+       int wps_nfc_dev_pw_id;
 
        /**
-        * home_milenage - Milenage parameters for SIM/USIM simulator in
-        *      <Ki>:<OPc>:<SQN> format
+        * 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;
+
+       /**
+        * sae_groups - Preference list of enabled groups for SAE
+        *
+        * By default (if this parameter is not set), the mandatory group 19
+        * (ECC group defined over a 256-bit prime order field) is preferred,
+        * but other groups are also enabled. If this parameter is set, the
+        * groups will be tried in the indicated order.
+        */
+       int *sae_groups;
+
+       /**
+        * dtim_period - Default DTIM period in Beacon intervals
+        *
+        * This parameter can be used to set the default value for network
+        * blocks that do not specify dtim_period.
+        */
+       int dtim_period;
+
+       /**
+        * beacon_int - Default Beacon interval in TU
+        *
+        * This parameter can be used to set the default value for network
+        * blocks that do not specify beacon_int.
+        */
+       int beacon_int;
+
+       /**
+        * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp
+        *
+        * This parameter can be used to define additional vendor specific
+        * elements for Beacon and Probe Response frames in AP/P2P GO mode. The
+        * format for these element(s) is a hexdump of the raw information
+        * elements (id+len+payload for one or more elements).
         */
-       char *home_milenage;
+       struct wpabuf *ap_vendor_elements;
+
+       /**
+        * ignore_old_scan_res - Ignore scan results older than request
+        *
+        * The driver may have a cache of scan results that makes it return
+        * information that is older than our scan trigger. This parameter can
+        * be used to configure such old information to be ignored instead of
+        * allowing it to update the internal BSS table.
+        */
+       int ignore_old_scan_res;
+
+       /**
+        * sched_scan_interval -  schedule scan interval
+        */
+       unsigned int sched_scan_interval;
 };
 
 
@@ -516,6 +908,13 @@ void wpa_config_set_blob(struct wpa_config *config,
 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
@@ -535,6 +934,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
  * wpa_config_read - Read and parse configuration database
  * @name: Name of the configuration (e.g., path and file name for the
  * configuration file)
+ * @cfgp: Pointer to previously allocated configuration data or %NULL if none
  * Returns: Pointer to allocated configuration data or %NULL on failure
  *
  * This function reads configuration data, parses its contents, and allocates
@@ -543,7 +943,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
  *
  * Each configuration backend needs to implement this function.
  */
-struct wpa_config * wpa_config_read(const char *name);
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp);
 
 /**
  * wpa_config_write - Write or update configuration data
index 8ea03ab..d03de0b 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
 #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;
+       }
+}
 
 
 /**
@@ -46,6 +66,15 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
        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. */
@@ -104,12 +133,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
                wpa_config_update_psk(ssid);
        }
 
-       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !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)) {
@@ -128,7 +151,7 @@ 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;
+       char buf[2000], *pos, *pos2;
 
        wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
                   *line);
@@ -184,6 +207,61 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
 }
 
 
+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)
@@ -267,21 +345,36 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
 
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
 {
        FILE *f;
-       char buf[256], *pos;
+       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)
+       if (name == NULL)
                return NULL;
+       if (cfgp)
+               config = cfgp;
+       else
+               config = wpa_config_alloc_empty(NULL, NULL);
+       if (config == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to allocate config file "
+                          "structure");
+               return NULL;
+       }
+       head = config->ssid;
+       cred_head = config->cred;
+
        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;
        }
@@ -308,10 +401,26 @@ struct wpa_config * wpa_config_read(const char *name)
                                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;
                        }
@@ -328,6 +437,7 @@ struct wpa_config * wpa_config_read(const char *name)
 
        config->ssid = head;
        wpa_config_debug_dump_networks(config);
+       config->cred = cred_head;
 
 #ifndef WPA_IGNORE_CONFIG_ERRORS
        if (errors) {
@@ -493,6 +603,18 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
 }
 
 
+#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;
@@ -509,9 +631,12 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *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);
@@ -560,13 +685,20 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
        INT(mode);
-       INT(proactive_key_caching);
+       INT(frequency);
+       write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
        INT(disabled);
        INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-       INT(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 */
+       INT(dtim_period);
+       INT(beacon_int);
 
 #undef STR
 #undef INT
@@ -574,6 +706,65 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 }
 
 
+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)
 {
@@ -590,6 +781,23 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
 #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
@@ -603,6 +811,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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)
@@ -614,6 +825,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
        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)
@@ -658,6 +873,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
        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)
@@ -682,6 +907,26 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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);
+       if (config->p2p_ignore_shared_freq)
+               fprintf(f, "p2p_ignore_shared_freq=%u\n",
+                       config->p2p_ignore_shared_freq);
 #endif /* CONFIG_P2P */
        if (config->country[0] && config->country[1]) {
                fprintf(f, "country=%c%c\n",
@@ -702,19 +947,11 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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->home_realm)
-               fprintf(f, "home_realm=%s\n", config->home_realm);
-       if (config->home_username)
-               fprintf(f, "home_username=%s\n", config->home_username);
-       if (config->home_password)
-               fprintf(f, "home_password=%s\n", config->home_password);
-       if (config->home_ca_cert)
-               fprintf(f, "home_ca_cert=%s\n", config->home_ca_cert);
-       if (config->home_imsi)
-               fprintf(f, "home_imsi=%s\n", config->home_imsi);
-       if (config->home_milenage)
-               fprintf(f, "home_milenage=%s\n", config->home_milenage);
        if (config->interworking)
                fprintf(f, "interworking=%u\n", config->interworking);
        if (!is_zero_ether_addr(config->hessid))
@@ -723,6 +960,77 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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_pw_from_config) {
+               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);
+       if (config->dtim_period)
+               fprintf(f, "dtim_period=%d\n", config->dtim_period);
+       if (config->beacon_int)
+               fprintf(f, "beacon_int=%d\n", config->beacon_int);
+
+       if (config->sae_groups) {
+               int i;
+               fprintf(f, "sae_groups=");
+               for (i = 0; config->sae_groups[i] >= 0; i++) {
+                       fprintf(f, "%s%d", i > 0 ? " " : "",
+                               config->sae_groups[i]);
+               }
+               fprintf(f, "\n");
+       }
+
+       if (config->ap_vendor_elements) {
+               int i, len = wpabuf_len(config->ap_vendor_elements);
+               const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
+               if (len > 0) {
+                       fprintf(f, "ap_vendor_elements=");
+                       for (i = 0; i < len; i++)
+                               fprintf(f, "%02x", *p++);
+                       fprintf(f, "\n");
+               }
+       }
+
+       if (config->ignore_old_scan_res)
+               fprintf(f, "ignore_old_scan_res=%d\n",
+                       config->ignore_old_scan_res);
+
+       if (config->freq_list && config->freq_list[0]) {
+               int i;
+               fprintf(f, "freq_list=");
+               for (i = 0; config->freq_list[i]; i++) {
+                       fprintf(f, "%s%u", i > 0 ? " " : "",
+                               config->freq_list[i]);
+               }
+               fprintf(f, "\n");
+       }
+       if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
+               fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+
+       if (config->sched_scan_interval)
+               fprintf(f, "sched_scan_interval=%u\n",
+                       config->sched_scan_interval);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -733,6 +1041,7 @@ 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 */
@@ -748,6 +1057,12 @@ int wpa_config_write(const char *name, struct wpa_config *config)
 
        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 */
index 2e9ccc0..2aac28f 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Configuration backend: empty starting point
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
 #include "base64.h"
 
 
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
 {
        struct wpa_config *config;
 
-       config = wpa_config_alloc_empty(NULL, NULL);
+       if (name == NULL)
+               return NULL;
+       if (cfgp)
+               config = cfgp;
+       else
+               config = wpa_config_alloc_empty(NULL, NULL);
        if (config == NULL)
                return NULL;
        /* TODO: fill in configuration data */
index 8419f43..1340dce 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Network configuration structures
  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CONFIG_SSID_H
                       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
  *
@@ -140,6 +142,14 @@ struct wpa_ssid {
        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;
@@ -157,6 +167,12 @@ struct wpa_ssid {
        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;
@@ -213,13 +229,18 @@ struct wpa_ssid {
         *
         * 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.
+        * 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;
 
@@ -308,6 +329,14 @@ struct wpa_ssid {
        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
@@ -333,6 +362,12 @@ struct wpa_ssid {
         *
         * 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 */
@@ -349,6 +384,8 @@ struct wpa_ssid {
         */
        int frequency;
 
+       int ht40;
+
        /**
         * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
         *
@@ -377,6 +414,20 @@ struct wpa_ssid {
        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
@@ -387,6 +438,24 @@ struct wpa_ssid {
        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;
@@ -408,6 +477,129 @@ struct wpa_ssid {
         * 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 */
+
+#ifdef CONFIG_VHT_OVERRIDES
+       /**
+        * disable_vht - Disable VHT (IEEE 802.11ac) for this network
+        *
+        * By default, use it if it is available, but this can be configured
+        * to 1 to have it disabled.
+        */
+       int disable_vht;
+
+       /**
+        * vht_capa - VHT capabilities to use
+        */
+       unsigned int vht_capa;
+
+       /**
+        * vht_capa_mask - mask for VHT capabilities
+        */
+       unsigned int vht_capa_mask;
+
+       int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2,
+           vht_rx_mcs_nss_3, vht_rx_mcs_nss_4,
+           vht_rx_mcs_nss_5, vht_rx_mcs_nss_6,
+           vht_rx_mcs_nss_7, vht_rx_mcs_nss_8;
+       int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2,
+           vht_tx_mcs_nss_3, vht_tx_mcs_nss_4,
+           vht_tx_mcs_nss_5, vht_tx_mcs_nss_6,
+           vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+       /**
+        * 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;
+
+       /**
+        * beacon_int - Beacon interval (default: 100 TU)
+        */
+       int beacon_int;
+
+       /**
+        * 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 */
index 5fb2580..3cf3a91 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Configuration backend: Windows registry
  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
@@ -208,6 +202,7 @@ static int wpa_config_read_global_os_version(struct wpa_config *config,
 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"),
@@ -277,6 +272,10 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
        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;
 }
 
@@ -350,13 +349,6 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
                wpa_config_update_psk(ssid);
        }
 
-       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !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)) {
@@ -442,7 +434,7 @@ static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
 }
 
 
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
 {
        TCHAR buf[256];
        int errors = 0;
@@ -450,7 +442,12 @@ struct wpa_config * wpa_config_read(const char *name)
        HKEY hk;
        LONG ret;
 
-       config = wpa_config_alloc_empty(NULL, NULL);
+       if (name == NULL)
+               return NULL;
+       if (cfgp)
+               config = cfgp;
+       else
+               config = wpa_config_alloc_empty(NULL, NULL);
        if (config == NULL)
                return NULL;
        wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
@@ -622,6 +619,9 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
        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;
 }
 
@@ -917,11 +917,13 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
        INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
        INT(mode);
-       INT(proactive_key_caching);
+       write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+                 -1);
        INT(disabled);
        INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-       INT(ieee80211w);
+       write_int(netw, "ieee80211w", ssid->ieee80211w,
+                 MGMT_FRAME_PROTECTION_DEFAULT);
 #endif /* CONFIG_IEEE80211W */
        STR(id_str);
 
index ebf9bbb..ab5feee 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -18,6 +12,7 @@
 #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 "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 "wpas_glue.h"
+#include "autoscan.h"
+#include "wnm_sta.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -60,12 +58,17 @@ static int pno_start(struct wpa_supplicant *wpa_s)
        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 (!ssid->disabled)
+               if (!wpas_network_disabled(wpa_s, ssid))
                        num_ssid++;
                ssid = ssid->next;
        }
@@ -87,7 +90,7 @@ static int pno_start(struct wpa_supplicant *wpa_s)
        i = 0;
        ssid = wpa_s->conf->ssid;
        while (ssid) {
-               if (!ssid->disabled) {
+               if (!wpas_network_disabled(wpa_s, ssid)) {
                        params.ssids[i].ssid = ssid->ssid;
                        params.ssids[i].ssid_len = ssid->ssid_len;
                        params.num_ssids++;
@@ -102,6 +105,9 @@ static int pno_start(struct wpa_supplicant *wpa_s)
                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)
@@ -112,10 +118,175 @@ static int pno_start(struct wpa_supplicant *wpa_s)
 
 static int pno_stop(struct wpa_supplicant *wpa_s)
 {
+       int ret = 0;
+
        if (wpa_s->pno) {
                wpa_s->pno = 0;
-               return wpa_drv_stop_sched_scan(wpa_s);
+               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;
 }
 
@@ -203,6 +374,60 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                        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);
@@ -228,6 +453,22 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
                        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 */
+#ifdef CONFIG_TESTING_GET_GTK
+       } else if (os_strcmp(cmd, "gtk") == 0) {
+               if (wpa_s->last_gtk_len == 0)
+                       return -1;
+               res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
+                                      wpa_s->last_gtk_len);
+               return res;
+#endif /* CONFIG_TESTING_GET_GTK */
        }
 
        if (res < 0 || (unsigned int) res >= buflen)
@@ -321,13 +562,12 @@ static int wpa_supplicant_ctrl_iface_tdls_setup(
        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);
-       }
+       wpa_tdls_remove(wpa_s->wpa, peer);
+
+       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;
 }
@@ -444,9 +684,21 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_AP
-       if (wpa_s->ap_iface)
+       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);
+                                                buf, buflen, timeout);
+       }
 #endif /* CONFIG_AP */
 
        if (pin) {
@@ -518,149 +770,455 @@ static int wpa_supplicant_ctrl_iface_wps_check_pin(
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
-       char *path, *method, *name;
+       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_config_token(
+       struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+       int ndef;
+       struct wpabuf *buf;
+       int res;
+       char *pos;
 
-       path = os_strchr(cmd, ' ');
-       if (path == NULL)
+       pos = os_strchr(cmd, ' ');
+       if (pos)
+               *pos++ = '\0';
+       if (os_strcmp(cmd, "WPS") == 0)
+               ndef = 0;
+       else if (os_strcmp(cmd, "NDEF") == 0)
+               ndef = 1;
+       else
                return -1;
-       *path++ = '\0';
 
-       method = os_strchr(path, ' ');
-       if (method == NULL)
+       buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
+       if (buf == NULL)
                return -1;
-       *method++ = '\0';
 
-       name = os_strchr(method, ' ');
-       if (name != NULL)
-               *name++ = '\0';
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
 
-       return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
+       return res;
 }
-#endif /* CONFIG_WPS_OOB */
 
 
-static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
-                                            char *cmd)
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+       struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
 {
-       u8 bssid[ETH_ALEN];
-       char *pin;
-       char *new_ssid;
-       char *new_auth;
-       char *new_encr;
-       char *new_key;
-       struct wps_new_ap_settings ap;
+       int ndef;
+       struct wpabuf *buf;
+       int res;
 
-       pin = os_strchr(cmd, ' ');
-       if (pin == NULL)
+       if (os_strcmp(cmd, "WPS") == 0)
+               ndef = 0;
+       else if (os_strcmp(cmd, "NDEF") == 0)
+               ndef = 1;
+       else
                return -1;
-       *pin++ = '\0';
 
-       if (hwaddr_aton(cmd, bssid)) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
-                          cmd);
+       buf = wpas_wps_nfc_token(wpa_s, ndef);
+       if (buf == NULL)
                return -1;
-       }
 
-       new_ssid = os_strchr(pin, ' ');
-       if (new_ssid == NULL)
-               return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
-       *new_ssid++ = '\0';
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
 
-       new_auth = os_strchr(new_ssid, ' ');
-       if (new_auth == NULL)
-               return -1;
-       *new_auth++ = '\0';
+       wpabuf_free(buf);
 
-       new_encr = os_strchr(new_auth, ' ');
-       if (new_encr == NULL)
+       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;
-       *new_encr++ = '\0';
+       len /= 2;
 
-       new_key = os_strchr(new_encr, ' ');
-       if (new_key == NULL)
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
                return -1;
-       *new_key++ = '\0';
+       if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+               wpabuf_free(buf);
+               return -1;
+       }
 
-       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);
+       ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+       wpabuf_free(buf);
+
+       return ret;
 }
 
 
-#ifdef CONFIG_AP
-static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
-                                               char *cmd, char *buf,
-                                               size_t buflen)
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len,
+                                             int cr)
 {
-       int timeout = 300;
-       char *pos;
-       const char *pin_txt;
+       struct wpabuf *buf;
+       int res;
 
-       if (!wpa_s->ap_iface)
+       buf = wpas_wps_nfc_handover_req(wpa_s, cr);
+       if (buf == NULL)
                return -1;
 
-       pos = os_strchr(cmd, ' ');
-       if (pos)
-               *pos++ = '\0';
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
 
-       if (os_strcmp(cmd, "disable") == 0) {
-               wpas_wps_ap_pin_disable(wpa_s);
-               return os_snprintf(buf, buflen, "OK\n");
-       }
+       wpabuf_free(buf);
 
-       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);
-       }
+       return res;
+}
 
-       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);
+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 || os_strcmp(pos, "WPS-CR") == 0) {
+               return wpas_ctrl_nfc_get_handover_req_wps(
+                       wpa_s, reply, max_len, os_strcmp(pos, "WPS-CR") == 0);
        }
 
        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)
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len,
+                                             int ndef, int cr, char *uuid)
 {
-       char *uuid = cmd, *pin, *pos;
-       u8 addr_buf[ETH_ALEN], *addr = NULL;
-       pin = os_strchr(uuid, ' ');
-       if (pin == NULL)
+       struct wpabuf *buf;
+       int res;
+
+       buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, 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;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+                                         char *cmd, char *reply,
+                                         size_t max_len)
+{
+       char *pos, *pos2;
+       int ndef;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "WPS") == 0)
+               ndef = 0;
+       else if (os_strcmp(cmd, "NDEF") == 0)
+               ndef = 1;
+       else
+               return -1;
+
+       pos2 = os_strchr(pos, ' ');
+       if (pos2)
+               *pos2++ = '\0';
+       if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+               return wpas_ctrl_nfc_get_handover_sel_wps(
+                       wpa_s, reply, max_len, ndef,
+                       os_strcmp(pos, "WPS-CR") == 0, pos2);
+       }
+
+       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;
+}
+
+
+static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
+                                        char *cmd)
+{
+       size_t len;
+       struct wpabuf *req, *sel;
+       int ret;
+       char *pos, *role, *type, *pos2;
+
+       role = cmd;
+       pos = os_strchr(role, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       type = pos;
+       pos = os_strchr(type, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       pos2 = os_strchr(pos, ' ');
+       if (pos2 == NULL)
+               return -1;
+       *pos2++ = '\0';
+
+       len = os_strlen(pos);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       req = wpabuf_alloc(len);
+       if (req == NULL)
+               return -1;
+       if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+               wpabuf_free(req);
+               return -1;
+       }
+
+       len = os_strlen(pos2);
+       if (len & 0x01) {
+               wpabuf_free(req);
+               return -1;
+       }
+       len /= 2;
+
+       sel = wpabuf_alloc(len);
+       if (sel == NULL) {
+               wpabuf_free(req);
+               return -1;
+       }
+       if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+               wpabuf_free(req);
+               wpabuf_free(sel);
+               return -1;
+       }
+
+       if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
+               ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+       } else {
+               wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+                          "reported: role=%s type=%s", role, type);
+               ret = -1;
+       }
+       wpabuf_free(req);
+       wpabuf_free(sel);
+
+       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, ' ');
@@ -739,6 +1297,43 @@ static int wpa_supplicant_ctrl_iface_wps_er_config(
        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 */
@@ -764,78 +1359,6 @@ static int wpa_supplicant_ctrl_iface_ibss_rsn(
 #endif /* CONFIG_IBSS_RSN */
 
 
-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 */
-}
-
-
 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
                                              char *rsp)
 {
@@ -971,8 +1494,18 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
 #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));
+#ifdef CONFIG_SAE
+       if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
+           wpa_s->sme.sae.state == SAE_ACCEPTED && !wpa_s->ap_iface) {
+               ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
+                                 wpa_s->sme.sae.group);
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_SAE */
+       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;
@@ -1001,6 +1534,57 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                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,
@@ -1229,10 +1813,12 @@ static int wpa_supplicant_ctrl_iface_list_networks(
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
                pos += ret;
-               ret = os_snprintf(pos, end - pos, "\t%s%s%s",
+               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)
@@ -1252,47 +1838,15 @@ static int wpa_supplicant_ctrl_iface_list_networks(
 
 static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
 {
-       int first = 1, ret;
+       int 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;
-       }
+       ret = wpa_write_ciphers(pos, end, cipher, "+");
+       if (ret < 0)
+               return pos;
+       pos += ret;
        return pos;
 }
 
@@ -1491,6 +2045,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
                        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));
@@ -1592,6 +2154,11 @@ static int wpa_supplicant_ctrl_iface_enable_network(
                                   "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);
 
@@ -1661,10 +2228,24 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 {
        int id;
        struct wpa_ssid *ssid;
+       int was_disabled;
 
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
+               if (wpa_s->sched_scanning)
+                       wpa_supplicant_cancel_sched_scan(wpa_s);
+
+               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+                       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+                       wpa_sm_set_config(wpa_s->wpa, NULL);
+                       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               }
                ssid = wpa_s->conf->ssid;
                while (ssid) {
                        struct wpa_ssid *remove_ssid = ssid;
@@ -1673,13 +2254,6 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                        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) {
-                       wpa_sm_set_config(wpa_s->wpa, NULL);
-                       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-                       wpa_supplicant_disassociate(wpa_s,
-                                                   WLAN_REASON_DEAUTH_LEAVING);
-               }
                return 0;
        }
 
@@ -1689,14 +2263,16 @@ static int wpa_supplicant_ctrl_iface_remove_network(
        ssid = wpa_config_get_network(wpa_s->conf, id);
        if (ssid)
                wpas_notify_network_removed(wpa_s, ssid);
-       if (ssid == NULL ||
-           wpa_config_remove_network(wpa_s->conf, id) < 0) {
+       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.
@@ -1708,7 +2284,23 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                wpa_sm_set_config(wpa_s->wpa, NULL);
                eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
+
+       was_disabled = ssid->disabled;
+
+       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;
+       }
+
+       if (!was_disabled && wpa_s->sched_scanning) {
+               wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
+                          "network from filters");
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
        }
 
        return 0;
@@ -1752,7 +2344,9 @@ static int wpa_supplicant_ctrl_iface_set_network(
                return -1;
        }
 
-       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+       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) {
                /*
@@ -1817,6 +2411,167 @@ static int wpa_supplicant_ctrl_iface_get_network(
 }
 
 
+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)
 {
@@ -1870,6 +2625,14 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
                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)
@@ -1918,6 +2681,14 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
                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)
@@ -2091,49 +2862,193 @@ static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
 }
 
 
-static int wpa_supplicant_ctrl_iface_get_capability(
-       struct wpa_supplicant *wpa_s, const char *_field, char *buf,
-       size_t buflen)
+static int ctrl_iface_get_capability_modes(int res, char *strict,
+                                          struct wpa_driver_capa *capa,
+                                          char *buf, size_t buflen)
 {
-       struct wpa_driver_capa capa;
-       int res;
-       char *strict;
-       char field[30];
+       int ret, first = 1;
+       char *pos, *end;
        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)
+       pos = buf;
+       end = pos + buflen;
+
+       if (res < 0) {
+               if (strict)
+                       return 0;
+               len = os_strlcpy(buf, "IBSS AP", buflen);
+               if (len >= buflen)
                        return -1;
+               return len;
        }
 
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
-               field, strict ? strict : "");
+       if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
+               ret = os_snprintf(pos, end - pos, "%sIBSS", first ? "" : " ");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+               first = 0;
+       }
 
-       if (os_strcmp(field, "eap") == 0) {
-               return eap_get_names(buf, buflen);
+       if (capa->flags & WPA_DRIVER_FLAGS_AP) {
+               ret = os_snprintf(pos, end - pos, "%sAP", first ? "" : " ");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+               first = 0;
        }
 
-       res = wpa_drv_get_capa(wpa_s, &capa);
+       return pos - buf;
+}
 
-       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);
+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;
 
-       if (os_strcmp(field, "key_mgmt") == 0)
-               return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
-                                                         buf, buflen);
+       pos = buf;
+       end = pos + buflen;
 
-       if (os_strcmp(field, "proto") == 0)
+       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 ctrl_iface_get_capability_freq(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:\n",
+                                 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 = %d MHz%s\n",
+                                         chnl[i].chan, chnl[i].freq,
+                                         chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
+                                         " (NO_IBSS)" : "");
+                       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);
 
@@ -2141,6 +3056,16 @@ static int wpa_supplicant_ctrl_iface_get_capability(
                return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
                                                          buf, buflen);
 
+       if (os_strcmp(field, "modes") == 0)
+               return ctrl_iface_get_capability_modes(res, strict, &capa,
+                                                      buf, buflen);
+
+       if (os_strcmp(field, "channels") == 0)
+               return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+
+       if (os_strcmp(field, "freq") == 0)
+               return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
                   field);
 
@@ -2183,167 +3108,394 @@ static char * anqp_add_hex(char *pos, char *end, const char *title,
 #endif /* CONFIG_INTERWORKING */
 
 
-static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
-                                        const char *cmd, char *buf,
-                                        size_t buflen)
+static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                         unsigned long mask, 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;
-                       }
-               }
+       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 (bss == NULL)
-               return 0;
+       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;
+       }
 
-       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;
+       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;
+       }
 
-       ie = (const u8 *) (bss + 1);
-       for (i = 0; i < bss->ie_len; i++) {
-               ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+       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 pos - buf;
+                       return 0;
                pos += ret;
        }
 
-       ret = os_snprintf(pos, end - pos, "\n");
-       if (ret < 0 || ret >= end - pos)
-               return pos - buf;
-       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;
+       }
 
-       ret = os_snprintf(pos, end - pos, "flags=");
-       if (ret < 0 || ret >= end - pos)
-               return pos - buf;
-       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;
+       }
 
-       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 (mask & WPA_BSS_MASK_NOISE) {
+               ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
                if (ret < 0 || ret >= end - pos)
-                       return pos - buf;
+                       return 0;
                pos += ret;
        }
-       if (bss->caps & IEEE80211_CAP_IBSS) {
-               ret = os_snprintf(pos, end - pos, "[IBSS]");
+
+       if (mask & WPA_BSS_MASK_LEVEL) {
+               ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
                if (ret < 0 || ret >= end - pos)
-                       return pos - buf;
+                       return 0;
                pos += ret;
        }
-       if (bss->caps & IEEE80211_CAP_ESS) {
-               ret = os_snprintf(pos, end - pos, "[ESS]");
+
+       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 pos - buf;
+                       return 0;
                pos += ret;
        }
-       if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
-               ret = os_snprintf(pos, end - pos, "[P2P]");
+
+       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 pos - buf;
+                       return 0;
                pos += ret;
        }
 
-       ret = os_snprintf(pos, end - pos, "\n");
-       if (ret < 0 || ret >= end - pos)
-               return pos - buf;
-       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;
 
-       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;
+               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 0;
+                       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
-       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;
+       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
-       ie = (const u8 *) (bss + 1);
-       ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
-       if (ret < 0 || ret >= end - pos)
-               return pos - buf;
-       pos += ret;
+       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 0;
+                       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 0;
+                       pos += ret;
+               }
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
+
 #ifdef CONFIG_INTERWORKING
-       pos = anqp_add_hex(pos, end, "anqp_venue_name", bss->anqp_venue_name);
-       pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
-                          bss->anqp_network_auth_type);
-       pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
-                          bss->anqp_roaming_consortium);
-       pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
-                          bss->anqp_ip_addr_type_availability);
-       pos = anqp_add_hex(pos, end, "anqp_nai_realm", bss->anqp_nai_realm);
-       pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
-       pos = anqp_add_hex(pos, end, "anqp_domain_name",
-                          bss->anqp_domain_name);
+       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 */
 
+       if (mask & WPA_BSS_MASK_DELIM) {
+               ret = os_snprintf(pos, end - pos, "====\n");
+               if (ret < 0 || ret >= end - pos)
+                       return 0;
+               pos += ret;
+       }
+
        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;
+                       }
+
+                       if (*(cmd + 6) == '-')
+                               id1 = 0;
+                       else
+                               id1 = atoi(cmd + 6);
+                       ctmp++;
+                       if (*ctmp >= '0' && *ctmp <= '9')
+                               id2 = atoi(ctmp);
+                       else
+                               id2 = (unsigned int) -1;
+                       bss = wpa_bss_get_id_range(wpa_s, id1, id2);
+                       if (id2 == (unsigned int) -1)
+                               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_strncmp(cmd, "FIRST", 5) == 0)
+               bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+       else if (os_strncmp(cmd, "LAST", 4) == 0)
+               bss = dl_list_last(&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) {
+                       if ((mask & WPA_BSS_MASK_DELIM) && len &&
+                           (bss == dl_list_last(&wpa_s->bss_id,
+                                                struct wpa_bss, list_id)))
+                               os_snprintf(buf - 5, 5, "####\n");
+                       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)
 {
@@ -2356,10 +3508,7 @@ static int wpa_supplicant_ctrl_iface_scan_interval(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
        int scan_int = atoi(cmd);
-       if (scan_int < 0)
-               return -1;
-       wpa_s->scan_interval = scan_int;
-       return 0;
+       return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
 }
 
 
@@ -2379,6 +3528,19 @@ static int wpa_supplicant_ctrl_iface_bss_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");
@@ -2420,7 +3582,13 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
 
-       bss = wpa_bss_get_bssid(wpa_s, bssid);
+       if (!ssid) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+                          "configuration known for the target AP");
+               return -1;
+       }
+
+       bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
        if (!bss) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
                           "from BSS table");
@@ -2432,12 +3600,6 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
         * 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);
 
@@ -2451,13 +3613,32 @@ 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;
 
-       return wpas_p2p_find(wpa_s, timeout, type, 0, NULL);
+       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);
 }
 
 
@@ -2470,14 +3651,19 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        enum p2p_wps_method wps_method;
        int new_pin;
        int ret;
-       int persistent_group;
+       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]
-        * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
+       /* <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;
@@ -2488,8 +3674,24 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        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) {
@@ -2521,11 +3723,16 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        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, join, auth, go_intent,
-                                  freq);
+                                  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;
@@ -2548,6 +3755,45 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
 }
 
 
+#if defined(TIZEN_EXT_ENROLLEE) && defined(CONFIG_WPS)
+static int p2p_ctrl_wps_enrollee(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+       u8 addr[ETH_ALEN];
+       char *pos;
+       char *pin = NULL;
+       enum p2p_wps_method wps_method;
+
+       /* <addr> [PIN#] <pbc |display|keypad> */
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       pos = cmd + 17;
+       if (*pos != ' ')
+               return -1;
+       pos++;
+
+       if (os_strstr(pos, "display")) {
+               wps_method = WPS_PIN_DISPLAY;
+       } else if (os_strstr(pos, "keypad")) {
+               wps_method = WPS_PIN_KEYPAD;
+       } else
+               wps_method = WPS_PBC;
+
+       if (wps_method == WPS_PIN_DISPLAY || wps_method == WPS_PIN_KEYPAD) {
+               pin = pos;
+               pin[8] = '\0';
+       }
+
+       if (wpas_p2p_wps_enrollee(wpa_s, addr, pin, wps_method))
+               return -1;
+
+       os_memcpy(buf, "OK\n", 3);
+       return 3;
+}
+#endif /* TIZEN_EXT_ENROLLEE && CONFIG_WPS */
+
+
 static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
 {
        unsigned int timeout = atoi(cmd);
@@ -2559,8 +3805,9 @@ 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] */
+       /* <addr> <config method> [join|auto] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -2570,8 +3817,12 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        pos++;
 
-       return wpas_p2p_prov_disc(wpa_s, addr, pos,
-                                 os_strstr(pos, "join") != NULL);
+       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);
 }
 
 
@@ -2620,6 +3871,10 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
                        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)
@@ -2708,6 +3963,8 @@ static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
 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;
 }
@@ -2876,7 +4133,9 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
        char *pos;
        int id;
        struct wpa_ssid *ssid;
-       u8 peer[ETH_ALEN];
+       u8 *_peer = NULL, peer[ETH_ALEN];
+       int freq = 0, pref_freq = 0;
+       int ht40;
 
        id = atoi(cmd);
        pos = os_strstr(cmd, " peer=");
@@ -2884,6 +4143,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
                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) {
@@ -2893,7 +4153,25 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        }
 
-       return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
+       pos = os_strstr(cmd, " freq=");
+       if (pos) {
+               pos += 6;
+               freq = atoi(pos);
+               if (freq <= 0)
+                       return -1;
+       }
+
+       pos = os_strstr(cmd, " pref=");
+       if (pos) {
+               pos += 6;
+               pref_freq = atoi(pos);
+               if (pref_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, pref_freq);
 }
 
 
@@ -2940,7 +4218,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-                                        char *cmd, int freq)
+                                        char *cmd, int freq, int ht40)
 {
        int id;
        struct wpa_ssid *ssid;
@@ -2954,26 +4232,31 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
+       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
 }
 
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-       int freq = 0;
+       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);
+               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);
+               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);
+               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);
@@ -2985,7 +4268,12 @@ 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;
+       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;
@@ -3005,8 +4293,116 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
                next = 0;
        }
 
-       return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next,
-                                buf, buflen);
+       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;
 }
 
 
@@ -3089,6 +4485,20 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                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;
@@ -3154,6 +4564,33 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                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);
 
@@ -3161,6 +4598,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
+{
+       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);
+}
+
+
 static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
 {
        char *pos, *pos2;
@@ -3189,81 +4635,302 @@ static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
                int2 = atoi(pos);
        }
 
-       return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
+       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 */
 
 
-static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
 {
+       u8 dst_addr[ETH_ALEN];
+       int used;
        char *pos;
-       unsigned int period = 0, interval = 0;
+       u32 subtypes = 0;
 
-       if (cmd[0]) {
-               pos = os_strchr(cmd, ' ');
-               if (pos == NULL)
+       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;
-               *pos++ = '\0';
-               period = atoi(cmd);
-               interval = atoi(pos);
+               subtypes |= BIT(num);
+               pos = os_strchr(pos + 1, ',');
+               if (pos == NULL)
+                       break;
+               pos++;
        }
 
-       return wpas_p2p_ext_listen(wpa_s, period, interval);
-}
+       if (subtypes == 0)
+               return -1;
 
-#endif /* CONFIG_P2P */
+       return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
 
 
-#ifdef CONFIG_INTERWORKING
-static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+                                   const u8 *addr, const char *realm)
 {
-       u8 bssid[ETH_ALEN];
-       struct wpa_bss *bss;
+       u8 *buf;
+       size_t rlen, len;
+       int ret;
 
-       if (hwaddr_aton(dst, bssid)) {
-               wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+       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);
 
-       bss = wpa_bss_get_bssid(wpa_s, bssid);
-       if (bss == NULL) {
-               wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
-                          MAC2STR(bssid));
-               return -1;
-       }
+       ret = hs20_anqp_send_req(wpa_s, addr,
+                                BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+                                buf, len);
 
-       return interworking_connect(wpa_s, bss);
+       os_free(buf);
+
+       return ret;
 }
 
 
-static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+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;
-       char *pos;
-#define MAX_ANQP_INFO_ID 100
-       u16 id[MAX_ANQP_INFO_ID];
-       size_t num_id = 0;
+       u8 *buf;
+       size_t len;
+       int ret;
 
        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)
+       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;
+       }
 
-       return anqp_send_req(wpa_s, dst_addr, id, num_id);
+       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_INTERWORKING */
+
+#endif /* CONFIG_HS20 */
 
 
 static int wpa_supplicant_ctrl_iface_sta_autoconnect(
@@ -3274,26 +4941,246 @@ static int wpa_supplicant_ctrl_iface_sta_autoconnect(
 }
 
 
+#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;
+}
+
+
+static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int query_reason;
+
+       query_reason = atoi(cmd);
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
+                  query_reason);
+
+       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+}
+
+#endif /* CONFIG_WNM */
+
+
+/* Get string representation of channel width */
+static const char * channel_width_name(enum chan_width width)
+{
+       switch (width) {
+       case CHAN_WIDTH_20_NOHT:
+               return "20 MHz (no HT)";
+       case CHAN_WIDTH_20:
+               return "20 MHz";
+       case CHAN_WIDTH_40:
+               return "40 MHz";
+       case CHAN_WIDTH_80:
+               return "80 MHz";
+       case CHAN_WIDTH_80P80:
+               return "80+80 MHz";
+       case CHAN_WIDTH_160:
+               return "160 MHz";
+       default:
+               return "unknown";
+       }
+}
+
+
 static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                                      size_t buflen)
 {
        struct wpa_signal_info si;
        int ret;
+       char *pos, *end;
 
        ret = wpa_drv_signal_poll(wpa_s, &si);
        if (ret)
                return -1;
 
-       ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+       pos = buf;
+       end = buf + buflen;
+
+       ret = os_snprintf(pos, end - pos, "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)
+       if (ret < 0 || ret > end - pos)
+               return -1;
+       pos += ret;
+
+       if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+               ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+                                 channel_width_name(si.chanwidth));
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+               ret = os_snprintf(pos, end - pos,
+                                 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
+                                 si.center_frq1, si.center_frq2);
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.avg_signal) {
+               ret = os_snprintf(pos, end - pos,
+                                 "AVG_RSSI=%d\n", si.avg_signal);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       return pos - buf;
+}
+
+
+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;
 }
 
 
+static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+
+#ifdef CONFIG_P2P
+       wpas_p2p_stop_find(wpa_s);
+       p2p_ctrl_flush(wpa_s);
+       wpas_p2p_group_remove(wpa_s, "*");
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS_TESTING
+       wps_version_number = 0x20;
+       wps_testing_dummy_cred = 0;
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_WPS
+       wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_TDLS_TESTING
+       extern unsigned int tdls_testing;
+       tdls_testing = 0;
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+       wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
+       wpa_tdls_enable(wpa_s->wpa, 1);
+#endif /* CONFIG_TDLS */
+
+       eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+       wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+
+       wpa_s->no_keep_alive = 0;
+
+       os_free(wpa_s->disallow_aps_bssid);
+       wpa_s->disallow_aps_bssid = NULL;
+       wpa_s->disallow_aps_bssid_count = 0;
+       os_free(wpa_s->disallow_aps_ssid);
+       wpa_s->disallow_aps_ssid = NULL;
+       wpa_s->disallow_aps_ssid_count = 0;
+
+       wpa_s->set_sta_uapsd = 0;
+       wpa_s->sta_uapsd = 0;
+
+       wpa_drv_radio_disable(wpa_s, 0);
+
+       wpa_bss_flush(wpa_s);
+       wpa_blacklist_clear(wpa_s);
+       wpa_s->extra_blacklist_count = 0;
+       wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
+       wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                         char *buf, size_t *resp_len)
 {
@@ -3303,7 +5190,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        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, "SET_NETWORK ", 12) == 0 ||
+           os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+           os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 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 {
@@ -3312,6 +5202,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        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);
@@ -3326,6 +5217,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        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;
@@ -3359,23 +5253,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "LOGOFF") == 0) {
                eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
        } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
-               wpa_s->normal_scans = 0;
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
-               else {
-                       wpa_s->disconnected = 0;
-                       wpa_s->reassociate = 1;
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
-               }
+               else
+                       wpas_request_connection(wpa_s);
        } else if (os_strcmp(buf, "RECONNECT") == 0) {
-               wpa_s->normal_scans = 0;
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
-               else if (wpa_s->disconnected) {
-                       wpa_s->disconnected = 0;
-                       wpa_s->reassociate = 1;
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
-               }
+               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))
@@ -3416,11 +5302,39 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
                if (wpas_wps_cancel(wpa_s))
                        reply_len = -1;
-#ifdef CONFIG_WPS_OOB
-       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-               if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
+#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_CONFIG_TOKEN ", 21) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+                       wpa_s, buf + 21, reply, reply_size);
+       } 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;
+       } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+               if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
                        reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
+#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;
@@ -3465,6 +5379,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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
@@ -3484,6 +5403,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
                reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
                                             reply_size);
+#if defined(TIZEN_EXT_ENROLLEE) && defined(CONFIG_WPS)
+       } else if (os_strncmp(buf, "WPS_ENROLLEE ", 13) == 0) {
+               wpa_printf(MSG_INFO , "[%s] : %s" , __func__ , buf);
+               reply_len = p2p_ctrl_wps_enrollee(wpa_s, buf + 13, reply, reply_size);
+#endif
        } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
                if (p2p_ctrl_listen(wpa_s, buf + 11))
                        reply_len = -1;
@@ -3494,7 +5418,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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))
+               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))
@@ -3539,10 +5463,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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);
+               p2p_ctrl_flush(wpa_s);
        } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
                if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
                        reply_len = -1;
@@ -3562,6 +5483,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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)
@@ -3578,7 +5507,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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(
@@ -3604,20 +5547,35 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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) {
-               wpa_s->normal_scans = 0;
+       } else if (os_strcmp(buf, "SCAN") == 0 ||
+                  os_strncmp(buf, "SCAN ", 5) == 0) {
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else {
-                       if (!wpa_s->scanning &&
+                       if (os_strlen(buf) > 4 &&
+                           os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0)
+                               wpa_s->scan_res_handler = scan_only_handler;
+                       if (!wpa_s->sched_scanning && !wpa_s->scanning &&
                            ((wpa_s->wpa_state <= WPA_SCANNING) ||
                             (wpa_s->wpa_state == WPA_COMPLETED))) {
-                               wpa_s->scan_req = 2;
+                               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 - "
@@ -3650,6 +5608,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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))
@@ -3682,6 +5652,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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);
@@ -3702,6 +5678,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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))
@@ -3716,8 +5695,27 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
                reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
                                                       reply_size);
+       } else if (os_strncmp(buf, "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;
+       } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
+               if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+                               reply_len = -1;
+#endif /* CONFIG_WNM */
+       } else if (os_strcmp(buf, "FLUSH") == 0) {
+               wpa_supplicant_ctrl_iface_flush(wpa_s);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -3823,7 +5821,7 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
        wpa_s = wpa_supplicant_get_iface(global, cmd);
        if (wpa_s == NULL)
                return -1;
-       return wpa_supplicant_remove_iface(global, wpa_s);
+       return wpa_supplicant_remove_iface(global, wpa_s, 0);
 }
 
 
@@ -3908,6 +5906,126 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
 }
 
 
+static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
+                                           const char *ifname,
+                                           char *cmd, size_t *resp_len)
+{
+       struct wpa_supplicant *wpa_s;
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (os_strcmp(ifname, wpa_s->ifname) == 0)
+                       break;
+       }
+
+       if (wpa_s == NULL) {
+               char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
+               if (resp)
+                       *resp_len = os_strlen(resp);
+               else
+                       *resp_len = 1;
+               return resp;
+       }
+
+       return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
+}
+
+
+static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
+                                              char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_P2P
+       static const char * cmd[] = {
+               "P2P_FIND",
+               "P2P_STOP_FIND",
+               "P2P_LISTEN",
+               "P2P_GROUP_ADD",
+               "P2P_GET_PASSPHRASE",
+               "P2P_SERVICE_UPDATE",
+               "P2P_SERVICE_FLUSH",
+               "P2P_FLUSH",
+               "P2P_CANCEL",
+               "P2P_PRESENCE_REQ",
+               "P2P_EXT_LISTEN",
+               NULL
+       };
+       static const char * prefix[] = {
+               "P2P_FIND ",
+               "P2P_CONNECT ",
+               "P2P_LISTEN ",
+               "P2P_GROUP_REMOVE ",
+               "P2P_GROUP_ADD ",
+               "P2P_PROV_DISC ",
+               "P2P_SERV_DISC_REQ ",
+               "P2P_SERV_DISC_CANCEL_REQ ",
+               "P2P_SERV_DISC_RESP ",
+               "P2P_SERV_DISC_EXTERNAL ",
+               "P2P_SERVICE_ADD ",
+               "P2P_SERVICE_DEL ",
+               "P2P_REJECT ",
+               "P2P_INVITE ",
+               "P2P_PEER ",
+               "P2P_SET ",
+               "P2P_UNAUTHORIZE ",
+               "P2P_PRESENCE_REQ ",
+               "P2P_EXT_LISTEN ",
+               NULL
+       };
+       int found = 0;
+       int i;
+
+       if (global->p2p_init_wpa_s == NULL)
+               return NULL;
+
+       for (i = 0; !found && cmd[i]; i++) {
+               if (os_strcmp(buf, cmd[i]) == 0)
+                       found = 1;
+       }
+
+       for (i = 0; !found && prefix[i]; i++) {
+               if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
+                       found = 1;
+       }
+
+       if (found)
+               return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+                                                        buf, resp_len);
+#endif /* CONFIG_P2P */
+       return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
+                                              char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+       if (global->p2p_init_wpa_s == NULL)
+               return NULL;
+       if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
+           os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
+               return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+                                                        buf, resp_len);
+#endif /* CONFIG_WIFI_DISPLAY */
+       return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
+                                          char *buf, size_t *resp_len)
+{
+       char *ret;
+
+       ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
+       if (ret)
+               return ret;
+
+       ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
+       if (ret)
+               return ret;
+
+       return NULL;
+}
+
+
 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                                                char *buf, size_t *resp_len)
 {
@@ -3916,6 +6034,20 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        int reply_len;
        int level = MSG_DEBUG;
 
+       if (os_strncmp(buf, "IFNAME=", 7) == 0) {
+               char *pos = os_strchr(buf + 7, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       return wpas_global_ctrl_iface_ifname(global,
+                                                            buf + 7, pos,
+                                                            resp_len);
+               }
+       }
+
+       reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
+       if (reply)
+               return reply;
+
        if (os_strcmp(buf, "PING") == 0)
                level = MSG_EXCESSIVE;
        wpa_hexdump_ascii(level, "RX global ctrl_iface",
index 88ae6b7..a329ef3 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / UNIX domain socket -based control interface
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_H
@@ -95,21 +89,6 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
 
 /**
- * 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);
-
-/**
  * 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
index 5f7e24d..dc02db2 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Windows Named Pipe -based control interface
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -429,7 +423,7 @@ static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
                                             const char *txt, size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
index 110ca4f..f3b660d 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / UDP socket -based control interface
  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -169,6 +163,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                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
@@ -180,6 +176,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                           "source %s", inet_ntoa(from.sin_addr));
                return;
        }
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
        buf[res] = '\0';
 
        if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -257,7 +255,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
                                             const char *txt, size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
@@ -272,6 +270,7 @@ 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)
@@ -291,13 +290,25 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 
        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);
-       addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#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);
@@ -448,6 +459,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                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
@@ -459,6 +472,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                           "source %s", inet_ntoa(from.sin_addr));
                return;
        }
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
        buf[res] = '\0';
 
        if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -508,6 +523,7 @@ 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)
@@ -529,13 +545,26 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 
        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);
-       addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+#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);
index 306a222..1b4b9b0 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -17,6 +11,8 @@
 #include <sys/stat.h>
 #include <grp.h>
 #include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
 #ifdef ANDROID
 #include <cutils/sockets.h>
 #endif /* ANDROID */
@@ -54,12 +50,20 @@ struct ctrl_iface_priv {
 };
 
 
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+struct ctrl_iface_global_priv {
+       struct wpa_global *global;
+       int sock;
+       struct dl_list ctrl_dst;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+                                          struct dl_list *ctrl_dst,
                                           int level, const char *buf,
                                           size_t len);
 
 
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
                                            struct sockaddr_un *from,
                                            socklen_t fromlen)
 {
@@ -71,7 +75,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
        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);
+       dl_list_add(ctrl_dst, &dst->list);
        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
                    (u8 *) from->sun_path,
                    fromlen - offsetof(struct sockaddr_un, sun_path));
@@ -79,13 +83,13 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
 }
 
 
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
                                            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) {
+       dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
                if (fromlen == dst->addrlen &&
                    os_memcmp(from->sun_path, dst->addr.sun_path,
                              fromlen - offsetof(struct sockaddr_un, sun_path))
@@ -152,14 +156,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
        buf[res] = '\0';
 
        if (os_strcmp(buf, "ATTACH") == 0) {
-               if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+               if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+                                                    fromlen))
                        reply_len = 1;
                else {
                        new_attached = 1;
                        reply_len = 2;
                }
        } else if (os_strcmp(buf, "DETACH") == 0) {
-               if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+               if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+                                                    fromlen))
                        reply_len = 1;
                else
                        reply_len = 2;
@@ -244,13 +250,30 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
                                             const char *txt, size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+       if (wpa_s == NULL)
                return;
-       wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+       if (global != 2 && wpa_s->global->ctrl_iface) {
+               struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+               if (!dl_list_empty(&priv->ctrl_dst)) {
+                       wpa_supplicant_ctrl_iface_send(global ? NULL :
+                                                      wpa_s->ifname,
+                                                      priv->sock,
+                                                      &priv->ctrl_dst,
+                                                      level, txt, len);
+               }
+       }
+
+       if (wpa_s->ctrl_iface == NULL)
+               return;
+       wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+                                      &wpa_s->ctrl_iface->ctrl_dst,
+                                      level, txt, len);
 }
 
 
@@ -265,6 +288,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        char *buf, *dir = NULL, *gid_str = NULL;
        struct group *grp;
        char *endp;
+       int flags;
 
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
@@ -308,6 +332,22 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                }
        }
 
+#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) {
@@ -381,7 +421,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               perror("supp-ctrl-iface-init: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -411,6 +451,20 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 #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);
@@ -492,14 +546,17 @@ free_dst:
 
 /**
  * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @ifname: Interface name for global control socket or %NULL
+ * @sock: Local socket fd
+ * @ctrl_dst: List of attached listeners
  * @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,
+static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+                                          struct dl_list *ctrl_dst,
                                           int level, const char *buf,
                                           size_t len)
 {
@@ -507,32 +564,45 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        char levelstr[10];
        int idx, res;
        struct msghdr msg;
-       struct iovec io[2];
+       struct iovec io[5];
 
-       if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+       if (sock < 0 || dl_list_empty(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;
+       idx = 0;
+       if (ifname) {
+               io[idx].iov_base = "IFNAME=";
+               io[idx].iov_len = 7;
+               idx++;
+               io[idx].iov_base = (char *) ifname;
+               io[idx].iov_len = os_strlen(ifname);
+               idx++;
+               io[idx].iov_base = " ";
+               io[idx].iov_len = 1;
+               idx++;
+       }
+       io[idx].iov_base = levelstr;
+       io[idx].iov_len = os_strlen(levelstr);
+       idx++;
+       io[idx].iov_base = (char *) buf;
+       io[idx].iov_len = len;
+       idx++;
        os_memset(&msg, 0, sizeof(msg));
        msg.msg_iov = io;
-       msg.msg_iovlen = 2;
+       msg.msg_iovlen = idx;
 
        idx = 0;
-       dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
-                             list) {
+       dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
                if (level >= dst->debug_level) {
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
                                    (u8 *) dst->addr.sun_path, dst->addrlen -
                                    offsetof(struct sockaddr_un, sun_path));
                        msg.msg_name = (void *) &dst->addr;
                        msg.msg_namelen = dst->addrlen;
-                       if (sendmsg(priv->sock, &msg, 0) < 0) {
+                       if (sendmsg(sock, &msg, 0) < 0) {
                                int _errno = errno;
                                wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
                                           "%d - %s",
@@ -542,7 +612,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                    (_errno != ENOBUFS && dst->errors > 10) ||
                                    _errno == ENOENT) {
                                        wpa_supplicant_ctrl_iface_detach(
-                                               priv, &dst->addr,
+                                               ctrl_dst, &dst->addr,
                                                dst->addrlen);
                                }
                        } else
@@ -575,8 +645,8 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
 
                if (os_strcmp(buf, "ATTACH") == 0) {
                        /* handle ATTACH signal of first monitor interface */
-                       if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
-                                                             fromlen)) {
+                       if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+                                                             &from, fromlen)) {
                                sendto(priv->sock, "OK\n", 3, 0,
                                       (struct sockaddr *) &from, fromlen);
                                /* OK to continue */
@@ -596,21 +666,16 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
 
 /* 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;
+       struct ctrl_iface_global_priv *priv = sock_ctx;
        char buf[256];
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
-       char *reply;
+       char *reply = NULL;
        size_t reply_len;
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -621,16 +686,32 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        }
        buf[res] = '\0';
 
-       reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-                                                        &reply_len);
+       if (os_strcmp(buf, "ATTACH") == 0) {
+               if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+                                                    fromlen))
+                       reply_len = 1;
+               else
+                       reply_len = 2;
+       } else if (os_strcmp(buf, "DETACH") == 0) {
+               if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+                                                    fromlen))
+                       reply_len = 1;
+               else
+                       reply_len = 2;
+       } else {
+               reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+                                                                &reply_len);
+       }
 
        if (reply) {
                sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
                       fromlen);
                os_free(reply);
-       } else if (reply_len) {
+       } else if (reply_len == 1) {
                sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
                       fromlen);
+       } else if (reply_len == 2) {
+               sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
        }
 }
 
@@ -640,24 +721,48 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 {
        struct ctrl_iface_global_priv *priv;
        struct sockaddr_un addr;
+       const char *ctrl = global->params.ctrl_interface;
 
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
                return NULL;
+       dl_list_init(&priv->ctrl_dst);
        priv->global = global;
        priv->sock = -1;
 
-       if (global->params.ctrl_interface == NULL)
+       if (ctrl == NULL)
                return priv;
 
+       wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
+
 #ifdef ANDROID
-       priv->sock = android_get_control_socket(global->params.ctrl_interface);
-       if (priv->sock >= 0)
+       if (os_strncmp(ctrl, "@android:", 9) == 0) {
+               priv->sock = android_get_control_socket(ctrl + 9);
+               if (priv->sock < 0) {
+                       wpa_printf(MSG_ERROR, "Failed to open Android control "
+                                  "socket '%s'", ctrl + 9);
+                       goto fail;
+               }
+               wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
+                          ctrl + 9);
                goto havesock;
-#endif /* ANDROID */
+       }
 
-       wpa_printf(MSG_DEBUG, "Global control interface '%s'",
-                  global->params.ctrl_interface);
+       if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
+               /*
+                * Backwards compatibility - try to open an Android control
+                * socket and if that fails, assume this was a UNIX domain
+                * socket instead.
+                */
+               priv->sock = android_get_control_socket(ctrl);
+               if (priv->sock >= 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Using Android control socket '%s'",
+                                  ctrl);
+                       goto havesock;
+               }
+       }
+#endif /* ANDROID */
 
        priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
@@ -670,46 +775,98 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        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 (os_strncmp(ctrl, "@abstract:", 10) == 0) {
+               addr.sun_path[0] = '\0';
+               os_strlcpy(addr.sun_path + 1, ctrl + 10,
+                          sizeof(addr.sun_path) - 1);
+               if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
+                   0) {
+                       wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
+                                  "bind(PF_UNIX) failed: %s", strerror(errno));
+                       goto fail;
+               }
+               wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
+                          ctrl + 10);
+               goto havesock;
+       }
+
+       os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
        if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
+               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) {
+                       if (unlink(ctrl) < 0) {
                                perror("unlink[ctrl_iface]");
                                wpa_printf(MSG_ERROR, "Could not unlink "
                                           "existing ctrl_iface socket '%s'",
-                                          global->params.ctrl_interface);
+                                          ctrl);
                                goto fail;
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               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);
+                                  ctrl);
                } 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);
+                                  ctrl);
                        goto fail;
                }
        }
 
-#ifdef ANDROID
+       wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
+
+       if (global->params.ctrl_interface_group) {
+               char *gid_str = global->params.ctrl_interface_group;
+               gid_t gid = 0;
+               struct group *grp;
+               char *endp;
+
+               grp = getgrnam(gid_str);
+               if (grp) {
+                       gid = grp->gr_gid;
+                       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;
+                       }
+                       wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+                                  (int) gid);
+               }
+               if (chown(ctrl, -1, gid) < 0) {
+                       perror("chown[global_ctrl_interface/ifname]");
+                       goto fail;
+               }
+
+               if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
+                       perror("chmod[global_ctrl_interface/ifname]");
+                       goto fail;
+               }
+       } else {
+               chmod(ctrl, S_IRWXU);
+       }
+
 havesock:
-#endif /* ANDROID */
        eloop_register_read_sock(priv->sock,
                                 wpa_supplicant_global_ctrl_iface_receive,
-                                global, NULL);
+                                global, priv);
 
        return priv;
 
@@ -724,11 +881,16 @@ fail:
 void
 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
 {
+       struct wpa_ctrl_dst *dst, *prev;
+
        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);
+       dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
+                             list)
+               os_free(dst);
        os_free(priv);
 }
diff --git a/wpa_supplicant/dbus/.gitignore b/wpa_supplicant/dbus/.gitignore
new file mode 100644 (file)
index 0000000..6db2468
--- /dev/null
@@ -0,0 +1 @@
+libwpadbus.a
index a088200..d64c65c 100644 (file)
@@ -50,18 +50,6 @@ 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= \
index 728fe06..c091234 100644 (file)
@@ -2,19 +2,7 @@
  "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
-        <policy user="0">
-                <allow own="fi.epitest.hostap.WPASupplicant"/>
-
-                <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
-                <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
-
-                <allow own="fi.w1.wpa_supplicant1"/>
-
-                <allow send_destination="fi.w1.wpa_supplicant1"/>
-                <allow send_interface="fi.w1.wpa_supplicant1"/>
-                <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
-        </policy>
-        <policy user="5000">
+        <policy user="root">
                 <allow own="fi.epitest.hostap.WPASupplicant"/>
 
                 <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
index 5850636..6caf740 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -23,6 +17,7 @@
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_old.h"
+#include "../wpa_supplicant_i.h"
 
 
 #ifndef SIGPOLL
@@ -263,6 +258,22 @@ static int integrate_with_eloop(struct wpas_dbus_priv *priv)
 }
 
 
+static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+                                           DBusMessage *message, void *data)
+{
+       struct wpas_dbus_priv *priv = data;
+
+       if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
+                                  "Disconnected")) {
+               wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
+               dbus_connection_set_exit_on_disconnect(conn, FALSE);
+               wpa_supplicant_terminate_proc(priv->global);
+               return DBUS_HANDLER_RESULT_HANDLED;
+       } else
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
 static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
 {
        DBusError error;
@@ -271,7 +282,10 @@ static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
        /* Get a reference to the system bus */
        dbus_error_init(&error);
        priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
-       if (!priv->con) {
+       if (priv->con) {
+               dbus_connection_add_filter(priv->con, disconnect_filter, priv,
+                                          NULL);
+       } else {
                wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
                           "bus: %s - %s", error.name, error.message);
                ret = -1;
@@ -310,6 +324,9 @@ static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
                                                    NULL, NULL, NULL);
                dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
                                                      NULL, NULL, NULL);
+               dbus_connection_remove_filter(priv->con, disconnect_filter,
+                                             priv);
+
                dbus_connection_unref(priv->con);
        }
 
index 50da09b..aea7db7 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DBUS_COMMON_H
index 9dab1ee..a551ccd 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DBUS_COMMON_I_H
@@ -25,6 +19,10 @@ struct wpas_dbus_priv {
        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 */
index 5f9e64a..61a9430 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -739,12 +733,12 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
 {
        dbus_uint32_t count = 0;
        dbus_bool_t success = FALSE;
-       char *buffer, *nbuffer;;
+       char *buffer, *nbuffer;
 
        entry->bytearray_value = NULL;
        entry->array_type = DBUS_TYPE_BYTE;
 
-       buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
+       buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
        if (!buffer)
                return FALSE;
 
@@ -754,8 +748,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
                char byte;
 
                if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
-                       nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
-                                            (count + BYTE_ARRAY_CHUNK_SIZE));
+                       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_"
@@ -801,7 +796,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
        entry->strarray_value = NULL;
        entry->array_type = DBUS_TYPE_STRING;
 
-       buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
+       buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
        if (buffer == NULL)
                return FALSE;
 
@@ -812,8 +807,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
                char *str;
 
                if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
-                       nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
-                                            (count + STR_ARRAY_CHUNK_SIZE));
+                       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_"
@@ -877,8 +873,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
 
                        buflen += BIN_ARRAY_CHUNK_SIZE;
 
-                       newbuf = os_realloc(entry->binarray_value,
-                                           buflen * BIN_ARRAY_ITEM_SIZE);
+                       newbuf = os_realloc_array(entry->binarray_value,
+                                                 buflen, BIN_ARRAY_ITEM_SIZE);
                        if (!newbuf)
                                goto cleanup;
                        entry->binarray_value = newbuf;
@@ -1104,5 +1100,5 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
                break;
        }
 
-       memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+       os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
 }
index 2f6eb45..9666349 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DBUS_DICT_HELPERS_H
index 6cb43a5..ddd2c82 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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
@@ -747,6 +834,111 @@ 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);
+}
+
+
+/**
+ * wpas_dbus_signal_sta - Send a station related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ * @sig_name: signal name - StaAuthorized or StaDeauthorized
+ *
+ * Notify listeners about event related with station
+ */
+static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
+                                const u8 *sta, const char *sig_name)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
+       char *dev_mac;
+
+       os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
+       dev_mac = sta_mac;
+
+       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, &dev_mac,
+                                    DBUS_TYPE_INVALID))
+               dbus_connection_send(iface->con, msg, NULL);
+       else
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+
+       wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
+                  sta_mac, sig_name);
+}
+
+
+/**
+ * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a new station has been authorized
+ */
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta)
+{
+       wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
+}
+
+
+/**
+ * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a station has been deauthorized
+ */
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta)
+{
+       wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
+}
+
+
 #ifdef CONFIG_P2P
 
 /**
@@ -867,7 +1059,7 @@ void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
                return;
 
        /* Check if this is a known peer */
-       if (p2p_get_peer_info(wpa_s->global->p2p, dev_addr, 0, NULL, 0) < 0)
+       if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
                goto error;
 
        os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -953,7 +1145,7 @@ static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
        if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
                return -1;
 
-       memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+       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,
@@ -982,7 +1174,6 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
        DBusMessage *msg;
        DBusMessageIter iter, dict_iter;
        struct wpas_dbus_priv *iface;
-       char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
        char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
 
        iface = wpa_s->parent->global->dbus;
@@ -1020,14 +1211,8 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
                                         client ? "client" : "GO"))
                goto nomem;
 
-       os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-                   wpa_s->parent->dbus_new_path, network_id);
-
        if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
                                             group_obj_path) ||
-          !wpa_dbus_dict_append_object_path(&dict_iter, "network_object",
-                                            net_obj_path) ||
           !wpa_dbus_dict_close_write(&iter, &dict_iter))
                goto nomem;
 
@@ -1357,7 +1542,7 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
                return;
 
        /* Check if this is a known peer */
-       if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+       if (!p2p_peer_known(wpa_s->global->p2p, sa))
                goto error;
 
        os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1426,7 +1611,7 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
                return;
 
        /* Check if this is a known peer */
-       if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+       if (!p2p_peer_known(wpa_s->global->p2p, sa))
                goto error;
 
        os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1607,10 +1792,12 @@ 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";
@@ -1633,6 +1820,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
        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);
@@ -1642,6 +1833,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
        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);
+       }
 }
 
 
@@ -1683,6 +1878,9 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
        case WPAS_DBUS_BSS_PROP_RSN:
                prop = "RSN";
                break;
+       case WPAS_DBUS_BSS_PROP_WPS:
+               prop = "WPS";
+               break;
        case WPAS_DBUS_BSS_PROP_IES:
                prop = "IEs";
                break;
@@ -1816,6 +2014,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
          wpas_dbus_getter_eap_methods,
          NULL
        },
+       { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+         wpas_dbus_getter_global_capabilities,
+         NULL
+       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -2029,11 +2231,11 @@ 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);
 
-#ifdef CONFIG_P2P
        /* 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);
@@ -2098,6 +2300,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
          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
@@ -2250,6 +2456,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  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,
          {
@@ -2279,6 +2491,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  END_ARGS
          }
        },
+#ifndef CONFIG_NO_CONFIG_BLOBS
        { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
          (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
          {
@@ -2302,21 +2515,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  END_ARGS
          }
        },
-
-       /*
-        * The supplicant dbus interface doesn't support a method to get link signal
-        * whereas socket interface does. For an external module to use dbus interface,
-        * this dbus method is added.
-        */
-#if defined TIZEN_EXT
-       { "GetLinkSignal", WPAS_DBUS_NEW_IFACE_INTERFACE,
-               (WPADBusMethodHandler) &wpas_dbus_handler_get_link_signal,
-               {
-                       { "siganl", "i", ARG_OUT},
-                       END_ARGS
-               }
-       },
-#endif
+#endif /* CONFIG_NO_CONFIG_BLOBS */
 #ifdef CONFIG_WPS
        { "Start", WPAS_DBUS_NEW_IFACE_WPS,
          (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
@@ -2502,6 +2701,41 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  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 */
+       { "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+         {
+                 END_ARGS
+         }
+       },
+       { "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+         {
+                 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 } }
 };
 
@@ -2570,6 +2804,14 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
          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,
@@ -2577,9 +2819,9 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
        },
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
-       { "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
-         wpas_dbus_getter_p2p_device_properties,
-         wpas_dbus_setter_p2p_device_properties
+       { "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,
@@ -2602,6 +2844,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
          NULL
        },
 #endif /* CONFIG_P2P */
+       { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+         wpas_dbus_getter_disconnect_reason,
+         NULL
+       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -2820,12 +3066,39 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
          }
        },
 #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
+         }
+       },
+       { "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
        { NULL, NULL, { END_ARGS } }
 };
 
@@ -2893,6 +3166,15 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
 
        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;
@@ -2908,8 +3190,36 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_P2P
 
 static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
-       { "Properties", WPAS_DBUS_NEW_IFACE_P2P_PEER, "a{sv}",
-         wpas_dbus_getter_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",
@@ -3109,10 +3419,37 @@ static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
          wpas_dbus_getter_p2p_group_members,
          NULL
        },
-       { "Properties",
-         WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
-         wpas_dbus_getter_p2p_group_properties,
-         wpas_dbus_setter_p2p_group_properties
+       { "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 }
 };
@@ -3234,10 +3571,6 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
 
 static const struct wpa_dbus_property_desc
 wpas_dbus_p2p_groupmember_properties[] = {
-       { "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
-         wpas_dbus_getter_p2p_group_properties,
-         NULL
-       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
index 62d1008..61c480a 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_DBUS_NEW_H
@@ -34,6 +28,7 @@ enum wpas_dbus_prop {
        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 {
@@ -44,6 +39,7 @@ enum wpas_dbus_bss_prop {
        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,
 };
 
@@ -114,13 +110,18 @@ enum wpas_dbus_bss_prop {
        WPAS_DBUS_NEW_INTERFACE ".BlobExists"
 #define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
        WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
-/*
- * The dbus error is added to handle an error case in the function wpas_dbus_handler_get_link_signal.
- */
-#if defined TIZEN_EXT
-#define WPAS_DBUS_ERROR_SIGNAL_UNKNOWN \
-       WPAS_DBUS_NEW_INTERFACE ".SignalUnknown"
-#endif
+
+#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
 
@@ -216,6 +217,15 @@ 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);
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta);
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta);
 
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
@@ -473,6 +483,32 @@ static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
 {
 }
 
+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)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
index 154a6d3..478d02f 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "../notify.h"
 #include "../bss.h"
 #include "../scan.h"
-#include "../ctrl_iface.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;
@@ -128,7 +123,7 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 static const char *dont_quote[] = {
        "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
        "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-       "bssid", NULL
+       "bssid", "scan_freq", "freq_list", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
@@ -253,7 +248,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 
                if ((os_strcmp(entry.key, "psk") == 0 &&
                     value[0] == '"' && ssid->ssid_len) ||
-                   (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+                   (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);
@@ -448,6 +443,76 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
 
 
 /**
+ * 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
@@ -477,25 +542,25 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
        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") &&
+               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 (!strcmp(entry.key, "Ifname") &&
+               } 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 (!strcmp(entry.key, "ConfigFile") &&
+               } 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 (!strcmp(entry.key, "BridgeIfname") &&
+               } 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);
@@ -543,6 +608,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
 out:
        os_free(driver);
        os_free(ifname);
+       os_free(confname);
        os_free(bridge_ifname);
        return reply;
 
@@ -576,7 +642,7 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
        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)) {
+       else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
                reply = wpas_dbus_error_unknown_error(
                        message, "wpa_supplicant couldn't remove this "
                        "interface.");
@@ -804,7 +870,7 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
                num++;
 
-       paths = os_zalloc(num * sizeof(char*));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -857,6 +923,44 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
 }
 
 
+/**
+ * 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)
 {
@@ -921,6 +1025,16 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
 
                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) {
@@ -1082,8 +1196,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
 
 #define FREQS_ALLOC_CHUNK 32
                if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
-                       nfreqs = os_realloc(freqs, sizeof(int) *
-                                           (freqs_num + FREQS_ALLOC_CHUNK));
+                       nfreqs = os_realloc_array(
+                               freqs, freqs_num + FREQS_ALLOC_CHUNK,
+                               sizeof(int));
                        if (nfreqs == NULL)
                                os_free(freqs);
                        freqs = nfreqs;
@@ -1103,8 +1218,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
                dbus_message_iter_next(&array_iter);
        }
 
-       nfreqs = os_realloc(freqs,
-                           sizeof(int) * (freqs_num + 1));
+       nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
        if (nfreqs == NULL)
                os_free(freqs);
        freqs = nfreqs;
@@ -1198,7 +1312,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                } else if (params.freqs && params.freqs[0]) {
                        wpa_supplicant_trigger_scan(wpa_s, &params);
                } else {
-                       wpa_s->scan_req = 2;
+                       wpa_s->scan_req = MANUAL_SCAN_REQ;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                }
        } else if (!os_strcmp(type, "active")) {
@@ -1206,6 +1320,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                        /* 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]: "
@@ -1325,6 +1442,28 @@ err:
 
 
 /**
+ * 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
@@ -1340,6 +1479,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        char *iface = NULL, *net_id = NULL;
        int id;
        struct wpa_ssid *ssid;
+       int was_disabled;
 
        dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
                              DBUS_TYPE_INVALID);
@@ -1347,13 +1487,15 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        /* 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 || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       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 == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1364,6 +1506,8 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
                goto out;
        }
 
+       was_disabled = ssid->disabled;
+
        wpas_notify_network_removed(wpa_s, ssid);
 
        if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -1379,6 +1523,13 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        if (ssid == wpa_s->current_ssid)
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
+       else if (!was_disabled && wpa_s->sched_scanning) {
+               wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
+                          "network from filters");
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
+
 
 out:
        os_free(iface);
@@ -1402,7 +1553,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
        }
 
        if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
 }
 
 
@@ -1417,6 +1569,9 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
 DBusMessage * wpas_dbus_handler_remove_all_networks(
        DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
+       if (wpa_s->sched_scanning)
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+
        /* NB: could check for failure and return an error */
        wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
        return NULL;
@@ -1446,13 +1601,15 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
        /* 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 || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       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 == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1501,13 +1658,15 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
        /* 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 || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       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 == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, net_id);
                goto out;
        }
@@ -1537,6 +1696,8 @@ out:
 }
 
 
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
 /**
  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
  * @message: Pointer to incoming dbus message
@@ -1701,77 +1862,110 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
 
 }
 
-/*
- * The supplicant dbus interface doesn't support a method to get link signal
- * whereas socket interface does. For an external module to use dbus interface,
- * this dbus method is added.
- */
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
 
-#if defined TIZEN_EXT
 /*
- * wpas_dbus_handler_get_link_signal - Get link signal
+ * 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: A dbus message containing an integer value(signal) or dbus error
+ * Returns: NULL
  *
- * Handler function for "GetLinkSignal" method call of network interface.
+ * Handler function for "FlushBSS" method call of network interface.
  */
-DBusMessage * wpas_dbus_handler_get_link_signal(DBusMessage *message,
-               struct wpa_supplicant *wpa_s)
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
 {
-       DBusMessage *reply = NULL;
-       DBusMessageIter iter;
-       struct wpa_signal_info si;
+       dbus_uint32_t age;
 
-       if(wpa_drv_signal_poll(wpa_s, &si)) {
-               return dbus_message_new_error(message,
-                                                       WPAS_DBUS_ERROR_SIGNAL_UNKNOWN,
-                                                       "Can't get siganl");
-       }
+       dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
+                             DBUS_TYPE_INVALID);
 
-       reply = dbus_message_new_method_return(message);
-       if (!reply) {
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-                                              NULL);
-               goto out;
-       }
+       if (age == 0)
+               wpa_bss_flush(wpa_s);
+       else
+               wpa_bss_flush_by_age(wpa_s, age);
 
-       dbus_message_iter_init_append(reply, &iter);
+       return NULL;
+}
 
-       if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
-                                                 &(si.current_signal))) {
-               dbus_message_unref(reply);
-               reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+
+#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);
-               goto out;
-       }
 
-out:
        return reply;
 }
-#endif
+#endif /* CONFIG_AUTOSCAN */
+
 
 /*
- * wpas_dbus_handler_flush_bss - Flush the BSS cache
+ * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
  * @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.
+ * Handler function for "EAPLogoff" method call of network interface.
  */
-DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
-                                         struct wpa_supplicant *wpa_s)
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s)
 {
-       dbus_uint32_t age;
-
-       dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
-                             DBUS_TYPE_INVALID);
+       eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+       return NULL;
+}
 
-       if (age == 0)
-               wpa_bss_flush(wpa_s);
-       else
-               wpa_bss_flush_by_age(wpa_s, age);
 
+/*
+ * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogin" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s)
+{
+       eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
        return NULL;
 }
 
@@ -1824,6 +2018,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                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"))
@@ -1865,6 +2065,12 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                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"))
@@ -2091,8 +2297,6 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                goto nomem;
        /***** Modes end */
 
-#if !defined TIZEN_EXT
-       /* Fix BCM4334 first scan */
        if (res >= 0) {
                dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
 
@@ -2100,7 +2304,6 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                                max_scan_ssid))
                        goto nomem;
        }
-#endif
 
        if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
                goto nomem;
@@ -2224,6 +2427,75 @@ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * 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
@@ -2287,7 +2559,7 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
                                              void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
-       dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
+       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);
@@ -2387,6 +2659,56 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * 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
@@ -2566,7 +2888,7 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
        unsigned int i = 0;
        dbus_bool_t success = FALSE;
 
-       paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+       paths = os_calloc(wpa_s->num_bss, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -2629,7 +2951,7 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
                if (!network_is_persistent_group(ssid))
                        num++;
 
-       paths = os_zalloc(num * sizeof(char *));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
                dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -2862,13 +3184,15 @@ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
 {
        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,
-                                               &res->level, error);
+                                               &level, error);
 }
 
 
@@ -2886,13 +3210,15 @@ dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
 {
        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,
-                                               &res->freq, error);
+                                               &freq, error);
 }
 
 
@@ -2957,7 +3283,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
 {
        DBusMessageIter iter_dict, variant_iter;
        const char *group;
-       const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
+       const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
        const char *key_mgmt[7]; /* max 7 key managements may be supported */
        int n;
 
@@ -3000,6 +3326,9 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
        case WPA_CIPHER_CCMP:
                group = "ccmp";
                break;
+       case WPA_CIPHER_GCMP:
+               group = "gcmp";
+               break;
        case WPA_CIPHER_WEP104:
                group = "wep104";
                break;
@@ -3017,6 +3346,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
                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))
@@ -3124,6 +3455,63 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *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
@@ -3283,3 +3671,139 @@ dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *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 */
index eb72abd..fbc8358 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
@@ -41,6 +35,12 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
                                                   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);
 
@@ -80,6 +80,10 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
 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);
 
@@ -94,6 +98,9 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 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);
 
@@ -115,19 +122,18 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s);
 
-/*
- * The supplicant dbus interface doesn't support a method to get link signal
- * whereas socket interface does. For an external module to use dbus interface,
- * this dbus method is added.
- */
-#if defined TIZEN_EXT
-DBusMessage * wpas_dbus_handler_get_link_signal(DBusMessage *message,
-                                           struct wpa_supplicant *wpa_s);
-#endif
-
 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);
+
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+                                         struct wpa_supplicant *wpa_s);
+
 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                          DBusError *error, void *user_data);
 
@@ -143,6 +149,18 @@ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
 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);
 
@@ -164,6 +182,14 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
 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);
 
@@ -222,6 +248,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
 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);
 
@@ -254,4 +283,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 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 */
index de0caad..6ec96df 100644 (file)
@@ -1,14 +1,9 @@
 /*
  * WPA Supplicant / dbus-based control interface (P2P)
+ * Copyright (c) 2011-2012, 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -45,7 +40,7 @@ static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
 
        if (!peer_path)
                return -1;
-       p = strrchr(peer_path, '/');
+       p = os_strrchr(peer_path, '/');
        if (!p)
                return -1;
        p++;
@@ -131,7 +126,8 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
                wpa_dbus_dict_entry_clear(&entry);
        }
 
-       wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
+       wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
+                     NULL, 0);
        os_free(req_dev_types);
        return reply;
 
@@ -350,13 +346,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
                if (ssid == NULL || ssid->disabled != 2)
                        goto inv_args;
 
-               if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+               if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+                                                 NULL)) {
                        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))
+       } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
                goto inv_args;
 
 out:
@@ -497,7 +494,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
 
        if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
            (parse_peer_object_path(peer_object_path, addr) < 0) ||
-           (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+           !p2p_peer_known(wpa_s->global->p2p, addr))
                goto inv_args;
 
        /*
@@ -507,8 +504,8 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
                goto inv_args;
 
        new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
-                                  persistent_group, join, authorize_only,
-                                  go_intent, freq);
+                                  persistent_group, 0, join, authorize_only,
+                                  go_intent, freq, -1, 0, 0);
 
        if (new_pin >= 0) {
                char npin[9];
@@ -603,8 +600,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
 
        if (!peer_object_path ||
            (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
-           (p2p_get_peer_info(wpa_s->global->p2p,
-                              peer_addr, 0, NULL, 0) < 0)) {
+           !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
                goto err;
        }
 
@@ -635,7 +631,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
                if (ssid == NULL || ssid->disabled != 2)
                        goto err;
 
-               if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
+               if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
+               {
                        reply = wpas_dbus_error_unknown_error(
                                message,
                                "Failed to reinvoke a persistent group");
@@ -692,7 +689,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
            os_strcmp(config_method, "pushbutton"))
                return wpas_dbus_error_invalid_args(message, NULL);
 
-       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
+       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");
 
@@ -704,9 +702,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
  * P2P Device property accessor methods.
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+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;
@@ -782,7 +780,7 @@ dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
                goto err_no_mem;
 
        /* Persistent Reconnect */
-       if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+       if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
                                       wpa_s->conf->persistent_reconnect))
                goto err_no_mem;
 
@@ -839,9 +837,9 @@ err_no_mem:
 }
 
 
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+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;
@@ -927,7 +925,7 @@ dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
                           (entry.type == DBUS_TYPE_UINT32) &&
                           (entry.uint32_value <= 15))
                        wpa_s->conf->p2p_go_intent = entry.uint32_value;
-               else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+               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) &&
@@ -1053,7 +1051,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
         * Now construct the peer object paths in a form suitable for
         * array_property_getter helper below.
         */
-       peer_obj_paths = os_zalloc(num * sizeof(char *));
+       peer_obj_paths = os_calloc(num, sizeof(char *));
 
        if (!peer_obj_paths) {
                out_of_mem = 1;
@@ -1140,13 +1138,18 @@ 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)
-               return FALSE;
+               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,
-                                               &wpa_s->dbus_groupobj_path,
-                                               error);
+                                               &dbus_groupobj_path, error);
 }
 
 
@@ -1157,11 +1160,13 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
        char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
        if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
-               return FALSE;
+               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));
 
-       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);
@@ -1172,14 +1177,13 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
  * Peer object properties accessor methods
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
-       DBusError *error, void *user_data)
+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;
-       DBusMessageIter variant_iter, dict_iter;
-       const struct p2p_peer_info *info = NULL;
-       const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
-       int i, num;
+       const struct p2p_peer_info *info;
+       char *tmp;
 
        if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
                return FALSE;
@@ -1188,68 +1192,264 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *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");
+               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,
-                                             "a{sv}", &variant_iter) ||
-           !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
-               goto err_no_mem;
+                                             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;
+       }
 
-       /* Fill out the dictionary */
-       if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
-                                        info->device_name))
-               goto err_no_mem;
-       if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
-                                            (char *)info->pri_dev_type,
-                                            WPS_DEV_TYPE_LEN))
-               goto err_no_mem;
-       if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
-                                        info->config_methods))
-               goto err_no_mem;
-       if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
-                                       info->level))
-               goto err_no_mem;
-       if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
-                                      info->dev_capab))
-               goto err_no_mem;
-       if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
-                                      info->group_capab))
-               goto err_no_mem;
+       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_dev_types =
+               int num_sec_device_types =
                        info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
-               DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
-                               iter_secdev_dict_array;
-
-               if (num_sec_dev_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 < num_sec_dev_types; i++) {
-                               wpa_dbus_dict_bin_array_add_element(
-                                               &iter_secdev_dict_array,
-                                               sec_dev_type_list,
-                                               WPS_DEV_TYPE_LEN);
-                               sec_dev_type_list += 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 (!wpa_dbus_dict_end_array(&dict_iter,
-                                               &iter_secdev_dict_entry,
-                                               &iter_secdev_dict_val,
-                                               &iter_secdev_dict_array))
-                               goto err_no_mem;
+                       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)
@@ -1258,29 +1458,24 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
                num++;
        }
 
-       if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
-                                              vendor_extension, num))
-               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;
+       if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                         vendor_extension,
+                                                         num, error))
+               return FALSE;
 
        return TRUE;
-
-err_no_mem:
-       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
-       return FALSE;
 }
 
 
 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; */
 
-       dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
-       return FALSE;
+       success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                        NULL, 0, error);
+       return success;
 }
 
 
@@ -1316,7 +1511,7 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
                if (network_is_persistent_group(ssid))
                        num++;
 
-       paths = os_zalloc(num * sizeof(char *));
+       paths = os_calloc(num, sizeof(char *));
        if (!paths) {
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
                return FALSE;
@@ -1608,9 +1803,11 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
        const u8 *addr;
        dbus_bool_t success = FALSE;
 
-       /* Ensure we are a GO */
-       if (wpa_s->wpa_state != WPA_COMPLETED)
-               return 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 */
@@ -1621,7 +1818,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
 
        num_members = p2p_get_group_num_members(wpa_s->p2p_group);
 
-       paths = os_zalloc(num_members * sizeof(char *));
+       paths = os_calloc(num_members, sizeof(char *));
        if (!paths)
                goto out_of_memory;
 
@@ -1658,53 +1855,145 @@ out_of_memory:
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+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;
-       DBusMessageIter variant_iter, dict_iter;
-       struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
-       const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
-       int num_vendor_ext = 0;
-       int i;
+       u8 role = wpas_get_p2p_role(wpa_s);
+       char *p_pass = NULL;
 
-       if (!hapd) {
-               dbus_set_error_const(error, DBUS_ERROR_FAILED,
-                                    "internal error");
-               return FALSE;
-       }
+       /* 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 = "";
 
-       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;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &p_pass, error);
 
-       /* 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)
-                       continue;
-               vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
+}
+
+
+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;
        }
 
-       if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
-                                              "WPSVendorExtensions",
-                                              vendor_ext, num_vendor_ext))
-               goto err_no_mem;
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     &p_psk, psk_len, error);
+}
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-           !dbus_message_iter_close_container(iter, &variant_iter))
-               goto err_no_mem;
 
-       return TRUE;
+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;
 
-err_no_mem:
-       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
-       return FALSE;
+       /* 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_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
                                                  DBusError *error,
                                                  void *user_data)
 {
@@ -1712,13 +2001,13 @@ dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
        DBusMessageIter variant_iter, iter_dict;
        struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
        unsigned int i;
-       struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+       struct hostapd_data *hapd = NULL;
 
-       if (!hapd) {
-               dbus_set_error_const(error, DBUS_ERROR_FAILED,
-                                    "internal error");
+       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))
@@ -1782,7 +2071,7 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
        if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                goto error;
 
-       if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
                if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
                        goto error;
 
@@ -1794,23 +2083,30 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
                                bonjour = 1;
                        else
                                goto error_clear;
-                       wpa_dbus_dict_entry_clear(&entry);
+               } 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) {
-               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);
-                       wpa_dbus_dict_entry_clear(&entry);
-               }
                if (version <= 0 || service == NULL)
                        goto error;
 
@@ -1818,37 +2114,15 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
                        goto error;
 
                os_free(service);
+               service = NULL;
        } 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 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 (query == NULL || resp == NULL)
                        goto error;
 
-               if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
-                       wpabuf_free(query);
-                       wpabuf_free(resp);
+               if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
                        goto error;
-               }
+               query = NULL;
+               resp = NULL;
        } else
                goto error;
 
@@ -1856,6 +2130,9 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
 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);
 }
 
@@ -1974,7 +2251,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
        struct wpabuf *tlv = NULL;
        u8 version = 0;
        u64 ref = 0;
-       u8 addr[ETH_ALEN];
+       u8 addr_buf[ETH_ALEN], *addr;
 
        dbus_message_iter_init(message, &iter);
 
@@ -2011,10 +2288,15 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
                wpa_dbus_dict_entry_clear(&entry);
        }
 
-       if (!peer_object_path ||
-           (parse_peer_object_path(peer_object_path, addr) < 0) ||
-           (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
-               goto error;
+       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)
@@ -2094,7 +2376,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
        }
        if (!peer_object_path ||
            (parse_peer_object_path(peer_object_path, addr) < 0) ||
-           (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+           !p2p_peer_known(wpa_s->global->p2p, addr))
                goto error;
 
        if (tlv == NULL)
index 206e904..a11b3c8 100644 (file)
@@ -1,15 +1,9 @@
-
 /*
  * WPA Supplicant / dbus-based control interface for p2p
+ * Copyright (c) 2011-2012, 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DBUS_NEW_HANDLERS_P2P_H
@@ -94,13 +88,13 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
 /*
  * P2P Device property accessor methods.
  */
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
 
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(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);
@@ -118,9 +112,36 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
 /*
  * P2P Peer properties.
  */
-dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data);
+
+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,
@@ -134,11 +155,31 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
                                               DBusError *error,
                                               void *user_data);
 
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+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_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
                                                  DBusError *error,
                                                  void *user_data);
 
index a72cfb3..4ad5e7e 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, Witold Sowa <witold.sowa@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -279,7 +273,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                        ret = wpa_supplicant_ap_wps_pin(wpa_s,
                                                        params.bssid,
                                                        params.pin,
-                                                       npin, sizeof(npin));
+                                                       npin, sizeof(npin), 0);
                else
 #endif /* CONFIG_AP */
                {
index e254365..cfa6a15 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, Witold Sowa <witold.sowa@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
index d6e7b48..6d31ad5 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, Witold Sowa <witold.sowa@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_DBUS_CTRL_H
index fb29f20..3b090c0 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -164,6 +158,12 @@ static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
                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);
@@ -251,7 +251,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
        DBusMessage *reply;
        struct wpabuf *xml;
 
-       xml = wpabuf_alloc(8000);
+       xml = wpabuf_alloc(10000);
        if (xml == NULL)
                return NULL;
 
index 71ab61e..85d8a78 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -274,10 +268,12 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
                        reply = wpas_dbus_iface_get_state(message, wpa_s);
                else if (!strcmp(method, "scanning"))
                        reply = wpas_dbus_iface_get_scanning(message, wpa_s);
+#ifndef CONFIG_NO_CONFIG_BLOBS
                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);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
 #ifdef CONFIG_WPS
                else if (!os_strcmp(method, "wpsPbc"))
                        reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
index 9523867..e668231 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_DBUS_H
index a7eabf3..e565de9 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -229,7 +223,7 @@ DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
                goto out;
        }
 
-       if (!wpa_supplicant_remove_iface(global, wpa_s)) {
+       if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
                reply = wpas_dbus_new_success_reply(message);
        } else {
                reply = dbus_message_new_error(message,
@@ -337,7 +331,7 @@ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
                                   struct wpa_supplicant *wpa_s)
 {
-       wpa_s->scan_req = 2;
+       wpa_s->scan_req = MANUAL_SCAN_REQ;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
        return wpas_dbus_new_success_reply(message);
 }
@@ -1306,6 +1300,8 @@ DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
 }
 
 
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
 /**
  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
  * @message: Pointer to incoming dbus message
@@ -1435,6 +1431,8 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
        return wpas_dbus_new_success_reply(message);
 }
 
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
 
 /**
  * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
index 009e807..825bc6d 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef CTRL_IFACE_DBUS_HANDLERS_H
index c04b844..bb79382 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface (WPS)
  * Copyright (c) 2006, Dan Williams <dcbw@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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 0e4e57f..a75918f 100644 (file)
@@ -1,4 +1,5 @@
 [D-BUS Service]
 Name=fi.epitest.hostap.WPASupplicant
+Exec=@BINDIR@/wpa_supplicant -u
 User=root
 SystemdService=wpa_supplicant.service
index 078e713..d97ff39 100644 (file)
@@ -1,4 +1,5 @@
 [D-BUS Service]
 Name=fi.w1.wpa_supplicant1
+Exec=@BINDIR@/wpa_supplicant -u
 User=root
 SystemdService=wpa_supplicant.service
index cff25d6..fe2e0db 100644 (file)
@@ -165,6 +165,9 @@ CONFIG_EAP_OTP=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
 
@@ -201,6 +204,8 @@ CONFIG_EAP_LEAP=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
@@ -217,6 +222,12 @@ CONFIG_SMARTCARD=y
 # 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
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
 # Development testing
 #CONFIG_EAPOL_TEST=y
 
@@ -224,6 +235,7 @@ CONFIG_SMARTCARD=y
 # 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.
@@ -249,11 +261,6 @@ CONFIG_CTRL_IFACE=y
 # 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
@@ -300,6 +307,9 @@ CONFIG_BACKEND=file
 # 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
@@ -312,9 +322,7 @@ CONFIG_BACKEND=file
 # 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.
+# IEEE 802.11w (management frame protection), also known as PMF
 # Driver support is also needed for IEEE 802.11w.
 #CONFIG_IEEE80211W=y
 
@@ -404,6 +412,16 @@ CONFIG_PEERKEY=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
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
 # Enable privilege separation (see README 'Privilege separation' for details)
 #CONFIG_PRIVSEP=y
 
@@ -415,7 +433,7 @@ CONFIG_PEERKEY=y
 # 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.
+# For BSD, uncomment these.
 #LIBS += -lexecinfo
 #LIBS_p += -lexecinfo
 #LIBS_c += -lexecinfo
@@ -424,7 +442,7 @@ CONFIG_PEERKEY=y
 # 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.
+# For BSD, uncomment these.
 #LIBS += -lbfd -liberty -lz
 #LIBS_p += -lbfd -liberty -lz
 #LIBS_c += -lbfd -liberty -lz
@@ -463,8 +481,51 @@ CONFIG_PEERKEY=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
+
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=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
+
+# Enable TDLS support
+#CONFIG_TDLS=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
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
new file mode 100644 (file)
index 0000000..8c3945c
--- /dev/null
@@ -0,0 +1,6 @@
+manpage.links
+manpage.refs
+*.8
+*.5
+*.html
+*.pdf
index f47235b..eb3a089 100644 (file)
 
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 1fe98f4..c080c07 100644 (file)
@@ -328,12 +328,12 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 41b5849..0ab6419 100644 (file)
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 402ea09..336c03b 100644 (file)
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 89b8a92..eb907a8 100644 (file)
@@ -137,12 +137,12 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 0ab4e15..aa20e57 100644 (file)
 
     <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>wext</term>
        <listitem>
          <para>Linux wireless extensions (generic).</para>
       </varlistentry>
 
       <varlistentry>
-       <term>broadcom</term>
-       <listitem>
-         <para>Broadcom wl.o driver.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>wired</term>
        <listitem>
          <para>wpa_supplicant wired Ethernet driver</para>
       <varlistentry>
        <term>-L</term>
        <listitem>
-         <para>Show license (GPL and BSD).</para>
+         <para>Show license (BSD).</para>
        </listitem>
       </varlistentry>
 
@@ -506,8 +477,8 @@ wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
 
 <blockquote><programlisting>
 wpa_supplicant \
-       -c wpa1.conf -i wlan0 -D hostap -N \
-       -c wpa2.conf -i ath0 -D madwifi
+       -c wpa1.conf -i wlan0 -D nl80211 -N \
+       -c wpa2.conf -i ath0 -D wext
 </programlisting></blockquote>
   </refsect1>
 
@@ -537,86 +508,6 @@ wpa_supplicant \
     <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>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
@@ -788,12 +679,12 @@ fi
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@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>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index d61b3fd..8036c07 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Internal driver interface wrappers
  * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DRIVER_I_H
@@ -135,6 +129,16 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
+                                    const u8 *addr, int reason_code)
+{
+       if (wpa_s->driver->sta_deauth) {
+               return wpa_s->driver->sta_deauth(wpa_s->drv_priv, NULL, addr,
+                                                reason_code);
+       }
+       return -1;
+}
+
 static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
                                         const u8 *addr, int reason_code)
 {
@@ -145,6 +149,7 @@ static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+#ifdef TIZEN_EXT
 static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
                                       const u8 *addr, int reason_code)
 {
@@ -154,6 +159,7 @@ static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
        }
        return -1;
 }
+#endif /* TIZEN_EXT */
 
 static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
                                    const u8 *bssid, const u8 *pmkid)
@@ -433,6 +439,13 @@ static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
        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)
@@ -462,6 +475,15 @@ static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
        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,
@@ -663,4 +685,30 @@ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
        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 */
diff --git a/wpa_supplicant/eap_proxy_dummy.mk b/wpa_supplicant/eap_proxy_dummy.mk
new file mode 100644 (file)
index 0000000..e69de29
index b3faaa1..d1eb4ff 100644 (file)
@@ -2,14 +2,8 @@
  * EAP method registration
  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -41,6 +35,11 @@ int eap_register_methods(void)
                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();
@@ -151,6 +150,11 @@ int eap_register_methods(void)
                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();
index 76f7527..dad2765 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
@@ -19,6 +13,7 @@
 #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"
@@ -26,7 +21,6 @@
 #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"
@@ -61,9 +55,8 @@ struct eapol_test_data {
        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;
+        /* last received EAP Response from Authentication Server */
+       struct wpabuf *last_eap_radius;
 
        u8 authenticator_pmk[PMK_LEN];
        size_t authenticator_pmk_len;
@@ -104,7 +97,7 @@ static int add_extra_attr(struct radius_msg *msg,
        size_t len;
        char *pos;
        u32 val;
-       char buf[128];
+       char buf[RADIUS_MAX_ATTR_LEN + 1];
 
        switch (attr->syntax) {
        case 's':
@@ -120,7 +113,7 @@ static int add_extra_attr(struct radius_msg *msg,
                if (pos[0] == '0' && pos[1] == 'x')
                        pos += 2;
                len = os_strlen(pos);
-               if ((len & 1) || (len / 2) > sizeof(buf)) {
+               if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) {
                        printf("Invalid extra attribute hexstring\n");
                        return -1;
                }
@@ -177,7 +170,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
                                          const u8 *eap, size_t len)
 {
        struct radius_msg *msg;
-       char buf[128];
+       char buf[RADIUS_MAX_ATTR_LEN + 1];
        const struct eap_hdr *hdr;
        const u8 *pos;
 
@@ -284,7 +277,9 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
                }
        }
 
-       radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
+       if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr)
+           < 0)
+               goto fail;
        return;
 
  fail:
@@ -433,6 +428,37 @@ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
 }
 
 
+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)
 {
@@ -460,6 +486,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
        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) {
@@ -492,7 +519,7 @@ static void test_eapol_clean(struct eapol_test_data *e,
        struct extra_radius_attr *p, *prev;
 
        radius_client_deinit(e->radius);
-       os_free(e->last_eap_radius);
+       wpabuf_free(e->last_eap_radius);
        radius_msg_free(e->last_recv_radius);
        e->last_recv_radius = NULL;
        os_free(e->eap_identity);
@@ -510,6 +537,10 @@ static void test_eapol_clean(struct eapol_test_data *e,
                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;
@@ -578,9 +609,8 @@ static char *eap_type_text(u8 type)
 
 static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
 {
-       u8 *eap;
-       size_t len;
-       struct eap_hdr *hdr;
+       struct wpabuf *eap;
+       const struct eap_hdr *hdr;
        int eap_type = -1;
        char buf[64];
        struct radius_msg *msg;
@@ -590,30 +620,29 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
 
        msg = e->last_recv_radius;
 
-       eap = radius_msg_get_eap(msg, &len);
+       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");
-               os_free(e->last_eap_radius);
+               wpabuf_free(e->last_eap_radius);
                e->last_eap_radius = NULL;
-               e->last_eap_radius_len = 0;
                return;
        }
 
-       if (len < sizeof(*hdr)) {
+       if (wpabuf_len(eap) < sizeof(*hdr)) {
                wpa_printf(MSG_DEBUG, "too short EAP packet "
                               "received from authentication server");
-               os_free(eap);
+               wpabuf_free(eap);
                return;
        }
 
-       if (len > sizeof(*hdr))
-               eap_type = eap[sizeof(*hdr)];
+       if (wpabuf_len(eap) > sizeof(*hdr))
+               eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
 
-       hdr = (struct eap_hdr *) eap;
+       hdr = wpabuf_head(eap);
        switch (hdr->code) {
        case EAP_CODE_REQUEST:
                os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
@@ -636,7 +665,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
                break;
        default:
                os_strlcpy(buf, "unknown EAP code", sizeof(buf));
-               wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
+               wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
                break;
        }
        wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
@@ -645,20 +674,21 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
 
        /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
 
-       os_free(e->last_eap_radius);
+       wpabuf_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);
+               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(len);
-               os_memcpy((u8 *) (dot1x + 1), eap, len);
+               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) + len);
+                                 (u8 *) dot1x,
+                                 sizeof(*dot1x) + wpabuf_len(eap));
                os_free(dot1x);
        }
 }
@@ -862,7 +892,7 @@ static int scard_test(void)
        unsigned char aka_ik[IK_LEN];
        unsigned char aka_ck[CK_LEN];
 
-       scard = scard_init(SCARD_TRY_BOTH);
+       scard = scard_init(SCARD_TRY_BOTH, NULL);
        if (scard == NULL)
                return -1;
        if (scard_set_pin(scard, "1234")) {
@@ -877,6 +907,9 @@ static int scard_test(void)
        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;
@@ -959,7 +992,7 @@ static int scard_get_triplets(int argc, char *argv[])
                wpa_debug_level = 99;
        }
 
-       scard = scard_init(SCARD_GSM_SIM_ONLY);
+       scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
        if (scard == NULL) {
                printf("Failed to open smartcard connection\n");
                return -1;
@@ -1139,7 +1172,7 @@ int main(int argc, char *argv[])
                        wait_for_monitor++;
                        break;
                case 'N':
-                       p1 = os_zalloc(sizeof(p1));
+                       p1 = os_zalloc(sizeof(*p1));
                        if (p1 == NULL)
                                break;
                        if (!p)
@@ -1199,7 +1232,7 @@ int main(int argc, char *argv[])
 
        os_memset(&wpa_s, 0, sizeof(wpa_s));
        eapol_test.wpa_s = &wpa_s;
-       wpa_s.conf = wpa_config_read(conf);
+       wpa_s.conf = wpa_config_read(conf, NULL);
        if (wpa_s.conf == NULL) {
                printf("Failed to parse configuration file '%s'.\n", conf);
                return -1;
@@ -1229,6 +1262,9 @@ int main(int argc, char *argv[])
        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);
 
index bd3a2bc..0f4d283 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -29,6 +23,7 @@
 #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 "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"
+
+
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+                                             int new_scan);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+
+
+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;
@@ -63,18 +85,32 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
                return -1;
        }
 
-       if (ssid->disabled) {
+       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);
+               if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+                                             wpa_ie, &wpa_ie_len) < 0)
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
        }
@@ -109,6 +145,8 @@ 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;
@@ -125,6 +163,12 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        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
@@ -142,6 +186,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        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;
 }
 
 
@@ -241,7 +287,8 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
                        if (eap->vendor == EAP_VENDOR_IETF) {
                                if (eap->method == EAP_TYPE_SIM)
                                        sim = 1;
-                               else if (eap->method == EAP_TYPE_AKA)
+                               else if (eap->method == EAP_TYPE_AKA ||
+                                        eap->method == EAP_TYPE_AKA_PRIME)
                                        aka = 1;
                        }
                        eap++;
@@ -250,7 +297,9 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
 
        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)
+       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) {
@@ -269,7 +318,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
        else
                type = SCARD_GSM_SIM_ONLY;
 
-       wpa_s->scard = scard_init(type);
+       wpa_s->scard = scard_init(type, NULL);
        if (wpa_s->scard == NULL) {
                wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
                        "(pcsc-lite)");
@@ -285,7 +334,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
 
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
-static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
+static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
                                        struct wpa_ssid *ssid)
 {
        int i, privacy = 0;
@@ -322,7 +371,7 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
 
 static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                                         struct wpa_ssid *ssid,
-                                        struct wpa_scan_res *bss)
+                                        struct wpa_bss *bss)
 {
        struct wpa_ie_data ie;
        int proto_match = 0;
@@ -340,7 +389,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                  ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
                 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
 
-       rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+       rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
                proto_match++;
 
@@ -384,7 +433,9 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
                if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-                   ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+                   (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;
@@ -395,7 +446,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
-       wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+       wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
                proto_match++;
 
@@ -441,6 +492,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                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");
@@ -491,7 +548,7 @@ static int ht_supported(const struct hostapd_hw_modes *mode)
 }
 
 
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
+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 };
@@ -529,7 +586,7 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
                return 0;
 
        for (i = 0; i < (int) sizeof(scan_ie); i++) {
-               rate_ie = wpa_scan_get_ie(bss, scan_ie[i]);
+               rate_ie = wpa_bss_get_ie(bss, scan_ie[i]);
                if (rate_ie == NULL)
                        continue;
 
@@ -582,37 +639,54 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
 }
 
 
+static int bss_is_dmg(struct wpa_bss *bss)
+{
+       return bss->freq > 45000;
+}
+
+
+/*
+ * Test whether BSS is in an ESS.
+ * This is done differently in DMG (60 GHz) and non-DMG bands
+ */
+static int bss_is_ess(struct wpa_bss *bss)
+{
+       if (bss_is_dmg(bss)) {
+               return (bss->caps & IEEE80211_CAP_DMG_MASK) ==
+                       IEEE80211_CAP_DMG_AP;
+       }
+
+       return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+               IEEE80211_CAP_ESS);
+}
+
+
 static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
-                                           int i, struct wpa_scan_res *bss,
+                                           int i, struct wpa_bss *bss,
                                            struct wpa_ssid *group)
 {
-       const u8 *ssid_;
-       u8 wpa_ie_len, rsn_ie_len, ssid_len;
+       u8 wpa_ie_len, rsn_ie_len;
        int wpa;
        struct wpa_blacklist *e;
        const u8 *ie;
        struct wpa_ssid *ssid;
 
-       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);
+       ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        wpa_ie_len = ie ? ie[1] : 0;
 
-       ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+       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(ssid_, ssid_len),
+               i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
                wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
-               wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+               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->conf) == 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
@@ -630,21 +704,39 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                }
        }
 
-       if (ssid_len == 0) {
+       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 (ssid->disabled) {
+               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 "
@@ -672,8 +764,8 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        check_ssid = 0;
 
                if (check_ssid &&
-                   (ssid_len != ssid->ssid_len ||
-                    os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
+                   (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;
                }
@@ -702,9 +794,8 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if (bss->caps & IEEE80211_CAP_IBSS) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "
-                               "network");
+               if (!bss_is_ess(bss)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - not ESS network");
                        continue;
                }
 
@@ -739,56 +830,51 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 
 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)
 {
-       size_t i;
+       unsigned int i;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
                group->priority);
 
-       for (i = 0; i < scan_res->num; i++) {
-               struct wpa_scan_res *bss = scan_res->res[i];
-               const u8 *ie, *ssid;
-               u8 ssid_len;
-
+       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;
-
-               ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
-               ssid = ie ? ie + 2 : (u8 *) "";
-               ssid_len = ie ? ie[1] : 0;
-
                wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
                        " ssid='%s'",
-                       MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
-               return wpa_bss_get(wpa_s, bss->bssid, ssid, ssid_len);
+                       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_scan_results *scan_res,
-                           struct wpa_ssid **selected_ssid)
+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, scan_res, wpa_s->conf->pssid[prio],
+                               wpa_s, wpa_s->conf->pssid[prio],
                                selected_ssid);
                        if (selected)
                                break;
                }
 
-               if (selected == NULL && wpa_s->blacklist) {
+               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);
@@ -804,15 +890,22 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
 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)) {
+       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);
 }
 
@@ -835,6 +928,15 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       wpa_msg(wpa_s, MSG_DEBUG,
+               "Considering connect request: reassociate: %d  selected: "
+               MACSTR "  bssid: " MACSTR "  pending: " MACSTR
+               "  wpa_state: %s  ssid=%p  current_ssid=%p",
+               wpa_s->reassociate, MAC2STR(selected->bssid),
+               MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+               wpa_supplicant_state_txt(wpa_s->wpa_state),
+               ssid, wpa_s->current_ssid);
+
        /*
         * Do not trigger new association unless the BSSID has changed or if
         * reassociation is requested. If we are in process of associating with
@@ -844,22 +946,21 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
            (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))) {
+             (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+              os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+              0) ||
+             (is_zero_ether_addr(wpa_s->pending_bssid) &&
+              ssid != wpa_s->current_ssid)))) {
                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_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+                       MAC2STR(selected->bssid));
                wpa_supplicant_associate(wpa_s, selected, ssid);
        } else {
-               wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
-                       "selected AP");
+               wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+                       "connect with the selected AP");
        }
 
        return 0;
@@ -875,7 +976,7 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
        for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
                for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
                {
-                       if (ssid->disabled)
+                       if (wpas_network_disabled(wpa_s, ssid))
                                continue;
                        if (ssid->mode == IEEE80211_MODE_IBSS ||
                            ssid->mode == IEEE80211_MODE_AP)
@@ -915,11 +1016,9 @@ static void wpa_supplicant_rsn_preauth_scan_results(
 
 static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                                       struct wpa_bss *selected,
-                                      struct wpa_ssid *ssid,
-                                      struct wpa_scan_results *scan_res)
+                                      struct wpa_ssid *ssid)
 {
-       size_t i;
-       struct wpa_scan_res *current_bss = NULL;
+       struct wpa_bss *current_bss = NULL;
        int min_diff;
 
        if (wpa_s->reassociate)
@@ -931,37 +1030,26 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        if (wpa_s->current_ssid != ssid)
                return 1; /* different network block */
 
-       /*
-        * Oct, 14th 2011. TIZEN
-        *
-        * Temporally, prevent to roam
-        */
-#if defined TIZEN_EXT
-       return 0;
-#endif
-
        if (wpas_driver_bss_selection(wpa_s))
                return 0; /* Driver-based roaming */
 
-       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 (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);
@@ -976,6 +1064,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                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)
@@ -996,16 +1090,23 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        }
 
        return 1;
+#else /* CONFIG_NO_ROAMING */
+       return 0;
+#endif /* CONFIG_NO_ROAMING */
 }
 
-/* Return < 0 if no scan results could be fetched. */
+
+/* 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)
+                                             union wpa_event_data *data,
+                                             int own_request)
 {
-       struct wpa_bss *selected;
-       struct wpa_ssid *ssid = NULL;
        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)
@@ -1015,22 +1116,30 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        wpa_supplicant_notify_scanning(wpa_s, 0);
 
 #ifdef CONFIG_P2P
-       if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
-           wpa_s->global->p2p != NULL) {
-               wpa_s->p2p_cb_on_scan_complete = 0;
+       if (own_request && 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)
+               if (wpa_s->conf->ap_scan == 2 || ap ||
+                   wpa_s->scan_res_handler == scan_only_handler)
+                       return -1;
+               if (!own_request)
                        return -1;
                wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
                        "scanning again");
@@ -1039,7 +1148,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        }
 
 #ifndef CONFIG_NO_RANDOM_POOL
-       size_t i, num;
        num = scan_res->num;
        if (num > 10)
                num = 10;
@@ -1055,7 +1163,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_NO_RANDOM_POOL */
 
-       if (wpa_s->scan_res_handler) {
+       if (own_request && wpa_s->scan_res_handler) {
                void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                                         struct wpa_scan_results *scan_res);
 
@@ -1064,7 +1172,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                scan_res_handler(wpa_s, scan_res);
 
                wpa_scan_results_free(scan_res);
-               return 0;
+               return -2;
        }
 
        if (ap) {
@@ -1083,11 +1191,21 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *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);
@@ -1100,15 +1218,28 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
-       selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
+       wpas_wps_update_ap_info(wpa_s, scan_res);
+
+       wpa_scan_results_free(scan_res);
+
+       return wpas_select_network_from_last_scan(wpa_s, 1);
+}
+
+
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+                                             int new_scan)
+{
+       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,
-                                                   scan_res);
-               wpa_scan_results_free(scan_res);
+               skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
                if (skip) {
-                       wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+                       if (new_scan)
+                               wpa_supplicant_rsn_preauth_scan_results(wpa_s);
                        return 0;
                }
 
@@ -1116,19 +1247,28 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                        wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
                        return -1;
                }
-               wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+               if (new_scan)
+                       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_scan_results_free(scan_res);
                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);
+                       if (new_scan)
+                               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
@@ -1141,6 +1281,19 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                                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);
@@ -1156,11 +1309,13 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        const char *rn, *rn2;
        struct wpa_supplicant *ifs;
 
-       if (_wpa_supplicant_event_scan_results(wpa_s, data) < 0) {
+       if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
                /*
                 * If no scan results could be fetched, then no need to
                 * notify those interfaces that did not actually request
-                * this scan.
+                * 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;
        }
@@ -1187,7 +1342,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                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);
+                       _wpa_supplicant_event_scan_results(ifs, data, 0);
                }
        }
 }
@@ -1195,11 +1350,114 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+       return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+       struct os_time now;
+
+       if (wpa_s->last_scan_res_used <= 0)
+               return -1;
+
+       os_get_time(&now);
+       if (now.sec - wpa_s->last_scan.sec > 5) {
+               wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
+               return -1;
+       }
+
+       return wpas_select_network_from_last_scan(wpa_s, 0);
+#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;
+#ifdef CONFIG_IEEE80211R
+       u8 bssid[ETH_ALEN];
+#endif /* CONFIG_IEEE80211R */
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
        if (data->assoc_info.req_ies)
@@ -1212,6 +1470,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                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",
@@ -1250,7 +1512,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 #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,
@@ -1308,6 +1569,23 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_SME */
 
+       /* Process FT when SME is in the driver */
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+           wpa_ft_is_completed(wpa_s->wpa)) {
+               if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+                   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;
+               }
+               wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done");
+       }
+
        wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
                             data->assoc_info.resp_ies_len);
 #endif /* CONFIG_IEEE80211R */
@@ -1364,13 +1642,50 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 }
 
 
+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;
-       int bssid_changed;
-       struct wpa_driver_capa capa;
 
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface) {
@@ -1383,53 +1698,55 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_AP */
 
-       /*
-        * Dec, 6th 2011. TIZEN
-        * If a wpa_supplicant is disconnec state, this associate event should be
-        * ignored and supplicant should be disconnected.
-        */
-#if defined TIZEN_EXT
-       if (wpa_s->wpa_state < WPA_ASSOCIATING) {
-               wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
-               return;
-       }
-#endif
-
        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 (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
-           os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+       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);
-               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);
+               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_supplicant_deauthenticate(
                                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);
+
+                       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
@@ -1470,6 +1787,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
            wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
            (wpa_s->current_ssid &&
             wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+               if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
+                   (wpa_s->drv_flags &
+                    WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
+                       /*
+                        * Set the key after having received joined-IBSS event
+                        * from the driver.
+                        */
+                       wpa_supplicant_set_wpa_none_key(wpa_s,
+                                                       wpa_s->current_ssid);
+               }
                wpa_supplicant_cancel_auth_timeout(wpa_s);
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
        } else if (!ft_completed) {
@@ -1507,6 +1834,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                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);
@@ -1528,8 +1857,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 
        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) {
+           wpa_s->current_ssid &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
                /* Set static WEP keys again */
                wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
        }
@@ -1551,6 +1880,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
        }
 #endif /* CONFIG_IBSS_RSN */
+
+       wpas_wps_notify_assoc(wpa_s, bssid);
 }
 
 
@@ -1561,49 +1892,69 @@ static int disconnect_reason_recoverable(u16 reason_code)
                reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
 }
 
-/*
- * Mar, 16th 2012. TIZEN
- * A supplicant tries to scan for specific access points after coming a disassoc event from a driver
- * However, it makes access point list of connman and wifi UI disappear
- * An unsetting scan ssid routine is patched
- * This makes wpa_supplicant carry full scan out.
- */
 
-/*
- * Start
- */
-#if defined TIZEN_EXT
-static void wpa_supplicant_unset_scan_ssid(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
+                                         u16 reason_code,
+                                         int locally_generated)
 {
-       struct wpa_ssid *start;
+       const u8 *bssid;
 
-       if (wpa_s == NULL)
-               return;
-       if (wpa_s->conf == NULL)
-               return;
-       if (wpa_s->conf->ssid == NULL)
+       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;
+       }
 
-       start = wpa_s->conf->ssid;
+       bssid = wpa_s->bssid;
+       if (is_zero_ether_addr(bssid))
+               bssid = wpa_s->pending_bssid;
 
-       while (start) {
-               start->scan_ssid = 0;
-               start = start->next;
+       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" : "");
        }
 }
-/*
- * Finish
- */
-#endif
 
-static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
-                                         u16 reason_code)
+
+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;
+#ifndef CONFIG_NO_SCAN_PROCESSING
        struct wpa_ssid *fast_reconnect_ssid = NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+       struct wpa_ssid *last_ssid;
 
        authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
        os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -1619,13 +1970,14 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-           wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+       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) {
+       if (!wpa_s->disconnected &&
+           (!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,
@@ -1633,6 +1985,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_COMPLETED &&
                    wpa_s->current_ssid &&
                    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+                   !locally_generated &&
                    disconnect_reason_recoverable(reason_code)) {
                        /*
                         * It looks like the AP has dropped association with
@@ -1641,35 +1994,20 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
                         * time for some common cases.
                         */
                        fast_reconnect = wpa_s->current_bss;
+#ifndef CONFIG_NO_SCAN_PROCESSING
                        fast_reconnect_ssid = wpa_s->current_ssid;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
                } 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");
+                               "immediate scan");
        } else {
                wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
-                               "try to re-connect");
+                       "try to re-connect");
                wpa_s->reassociate = 0;
                wpa_s->disconnected = 1;
-               /*
-                * Mar, 16th 2012. TIZEN
-                * A supplicant tries to scan for specific access points after coming a disassoc event from a driver
-                * However, it makes access point list of connman and wifi UI disappear
-                * An unsetting scan ssid routine is patched
-                * This makes wpa_supplicant carry full scan out.
-                */
-
-               /*
-                * Start
-                */
-#if defined TIZEN_EXT
-               wpa_supplicant_unset_scan_ssid(wpa_s);
-               wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
-               /*
-                * Finish
-                */
-#endif
+               wpa_supplicant_cancel_sched_scan(wpa_s);
        }
        bssid = wpa_s->bssid;
        if (is_zero_ether_addr(bssid))
@@ -1677,18 +2015,23 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
        if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
                wpas_connection_failed(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
-               " reason=%d",
-               MAC2STR(bssid), reason_code);
+       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))
+       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
@@ -1748,6 +2091,9 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
 
                /* initialize countermeasures */
                wpa_s->countermeasures = 1;
+
+               wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
                wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
 
                /*
@@ -1839,11 +2185,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
                        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
@@ -1880,10 +2228,14 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
                return;
        switch (data->tdls.oper) {
        case TDLS_REQUEST_SETUP:
-               wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+               wpa_tdls_remove(wpa_s->wpa, data->tdls.peer);
+               if (wpa_tdls_is_external_setup(wpa_s->wpa))
+                       wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+               else
+                       wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
                break;
        case TDLS_REQUEST_TEARDOWN:
-               wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+               wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
                                       data->tdls.reason_code);
                break;
        }
@@ -1891,6 +2243,25 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
 #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,
@@ -2011,59 +2382,17 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
-{
-       u8 action, mode;
-       const u8 *pos, *end;
-
-       if (rx->data == NULL || rx->len == 0)
-               return;
-
-       pos = rx->data;
-       end = pos + rx->len;
-       action = *pos++;
-
-       wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
-                  action, MAC2STR(rx->sa));
-       switch (action) {
-       case WNM_BSS_TRANS_MGMT_REQ:
-               if (pos + 5 > end)
-                       break;
-               wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
-                          "Request: dialog_token=%u request_mode=0x%x "
-                          "disassoc_timer=%u validity_interval=%u",
-                          pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
-               mode = pos[1];
-               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)");
-                               break;
-                       }
-                       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);
-               }
-               break;
-       }
-}
-
-
 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_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);
@@ -2074,8 +2403,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 {
        int level = MSG_DEBUG;
 
-       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
-           data->rx_mgmt.frame_len >= 24) {
+       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;
@@ -2099,10 +2427,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
        case EVENT_DISASSOC:
                wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
-
                if (data) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
-                               data->disassoc_info.reason_code);
+                       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));
@@ -2113,9 +2442,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                               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);
@@ -2123,7 +2459,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        wpas_p2p_disassoc_notif(
                                wpa_s, data->disassoc_info.addr, reason_code,
                                data->disassoc_info.ie,
-                               data->disassoc_info.ie_len);
+                               data->disassoc_info.ie_len,
+                               locally_generated);
 #endif /* CONFIG_P2P */
                }
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2135,8 +2472,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                "Deauthentication notification");
                        if (data) {
                                reason_code = data->deauth_info.reason_code;
-                               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
-                                       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,
@@ -2147,14 +2488,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                            "Deauthentication frame IE(s)",
                                            data->deauth_info.ie,
                                            data->deauth_info.ie_len);
-#ifdef CONFIG_P2P
-                               wpas_p2p_deauth_notif(
-                                       wpa_s, data->deauth_info.addr,
-                                       reason_code,
-                                       data->deauth_info.ie,
-                                       data->deauth_info.ie_len);
-#endif /* CONFIG_P2P */
                        }
+                       wpa_reset_ft_completed(wpa_s->wpa);
                }
 #ifdef CONFIG_AP
                if (wpa_s->ap_iface && data && data->deauth_info.addr) {
@@ -2162,8 +2497,38 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                               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);
+               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);
@@ -2171,6 +2536,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #ifndef CONFIG_NO_SCAN_PROCESSING
        case EVENT_SCAN_RESULTS:
                wpa_supplicant_event_scan_results(wpa_s, data);
+               if (wpa_s->wpa_state != WPA_AUTHENTICATING &&
+                   wpa_s->wpa_state != WPA_ASSOCIATING)
+                       wpas_p2p_continue_after_scan(wpa_s);
                break;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
        case EVENT_ASSOCINFO:
@@ -2192,6 +2560,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                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);
@@ -2214,6 +2587,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                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);
+               }
+#if defined TIZEN_EXT
+               wpa_supplicant_cancel_auth_timeout(wpa_s);
+               /* Clear the states */
+               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, 1, 0);
+#endif
                break;
        case EVENT_AUTH_TIMED_OUT:
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2298,15 +2686,32 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
                                       data->rx_from_unknown.wds);
                break;
-       case EVENT_RX_MGMT:
+       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
-                       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 (stype == WLAN_FC_STYPE_PROBE_REQ &&
                            data->rx_mgmt.frame_len > 24) {
                                const u8 *src = mgmt->sa;
@@ -2314,8 +2719,29 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                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);
+#ifdef TIZEN_EXT_P2P
+                               wpa_printf(MSG_DEBUG, "Non-AP: Probe request frame ");
+                       {
+                               /* If we are Go or client, we need not reply the probe reqest on eth0 interface */
+                               struct wpa_supplicant* ifs;
+                               int ignore = 0;
+                               for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+                                       if ( (ifs->p2p_group_interface == P2P_GROUP_INTERFACE_GO ) ||(ifs->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT )) {
+                                               wpa_printf(MSG_DEBUG, "Non-AP: NEERAJKG Ignoring Probe request");
+                                               ignore = 1;
+                                               break;
+                                       }
+                               }
+                               if(ignore)
+                                       break;
+                               else
+                                       wpa_printf(MSG_DEBUG, "Non-AP: Couln't Ignore Probe request %d", wpa_s->p2p_group_interface);
+                       }
+#endif
+                               wpas_p2p_probe_req_rx(
+                                       wpa_s, src, mgmt->da,
+                                       mgmt->bssid, ie, ie_len,
+                                       data->rx_mgmt.ssi_signal);
                                break;
                        }
 #endif /* CONFIG_P2P */
@@ -2323,8 +2749,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                "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
@@ -2349,6 +2789,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                }
 #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,
@@ -2357,10 +2803,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                 data->rx_action.freq) == 0)
                        break;
 #endif /* CONFIG_GAS */
-               if (data->rx_action.category == WLAN_ACTION_WNM) {
-                       wnm_action_rx(wpa_s, &data->rx_action);
-                       break;
-               }
 #ifdef CONFIG_TDLS
                if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
                    data->rx_action.len >= 4 &&
@@ -2391,7 +2833,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                             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.ie_len,
+                                            data->rx_probe_req.ssi_signal);
                        break;
                }
 #endif /* CONFIG_AP */
@@ -2400,7 +2843,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                      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.ie_len,
+                                     data->rx_probe_req.ssi_signal);
 #endif /* CONFIG_P2P */
                break;
        case EVENT_REMAIN_ON_CHANNEL:
@@ -2528,6 +2972,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        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 */
@@ -2588,6 +3037,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                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.
@@ -2600,6 +3052,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpas_wps_start_pbc(wpa_s, NULL, 0);
 #endif /* CONFIG_WPS */
                break;
+       case EVENT_CONNECT_FAILED_REASON:
+#ifdef CONFIG_AP
+               if (!wpa_s->ap_iface || !data)
+                       break;
+               hostapd_event_connect_failed_reason(
+                       wpa_s->ap_iface->bss[0],
+                       data->connect_failed_reason.addr,
+                       data->connect_failed_reason.code);
+#endif /* CONFIG_AP */
+               break;
        default:
                wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
                break;
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
new file mode 100755 (executable)
index 0000000..5ac9859
--- /dev/null
@@ -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()
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
new file mode 100644 (file)
index 0000000..59b0a9d
--- /dev/null
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# Tests p2p_connect
+# Will try to connect to another peer
+# and form a group
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> -m <wps_method> \ " \
+               % sys.argv[0]
+       print "         -a <addr> [-p <pin>] [-g <go_intent>] \ "
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -m = wps method"
+       print "  -a = peer address"
+       print "  -p = pin number (8 digits)"
+       print "  -g = group owner intent"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+
+
+# Required Signals
+def GONegotiationSuccess(status):
+       print "Go Negotiation Success"
+
+def GONegotiationFailure(status):
+       print 'Go Negotiation Failed. Status:'
+       print format(status)
+       os._exit(0)
+
+def GroupStarted(properties):
+       if properties.has_key("group_object"):
+               print 'Group Formation Complete %s' \
+                       % properties["group_object"]
+       os._exit(0)
+
+def WpsFailure(status, etc):
+       print "WPS Authentication Failure".format(status)
+       print etc
+       os._exit(0)
+
+class P2P_Connect():
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global ifname
+       global wpas
+       global wpas_dbus_interface
+       global timeout
+       global path
+       global wps_method
+       global go_intent
+       global addr
+       global pin
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Dictionary of Arguements
+       global p2p_connect_arguements
+
+       # Constructor
+       def __init__(self,ifname,wpas_dbus_interface,addr,
+                                       pin,wps_method,go_intent):
+               # Initializes variables and threads
+               self.ifname = ifname
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.wps_method = wps_method
+               self.go_intent = go_intent
+               self.addr = addr
+               self.pin = pin
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = \
+                       "/" + self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = \
+                       self.wpas_dbus_opath + "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                       self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                       self.wpas_dbus_interfaces_interface + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(
+                               self.wpas_object, self.wpas_dbus_interface)
+
+               # See if wpa_supplicant already knows about this interface
+               self.path = None
+               try:
+                       self.path = self.wpas.GetInterface(ifname)
+               except:
+                       if not str(exc).startswith(
+                               self.wpas_dbus_interface + \
+                               ".InterfaceUnknown:"):
+                               raise exc
+                       try:
+                               path = self.wpas.CreateInterface(
+                                       {'Ifname': ifname, 'Driver': 'test'})
+                               time.sleep(1)
+
+                       except dbus.DBusException, exc:
+                               if not str(exc).startswith(
+                                       self.wpas_dbus_interface + \
+                                       ".InterfaceExists:"):
+                                       raise exc
+
+               # Get Interface and objects
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface,self.path)
+               self.p2p_interface = dbus.Interface(
+                               self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               # Add signals
+               self.bus.add_signal_receiver(GONegotiationSuccess,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="GONegotiationSuccess")
+               self.bus.add_signal_receiver(GONegotiationFailure,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="GONegotiationFailure")
+               self.bus.add_signal_receiver(GroupStarted,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="GroupStarted")
+               self.bus.add_signal_receiver(WpsFailure,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="WpsFailed")
+
+
+       #Constructing all the arguements needed to connect
+       def constructArguements(self):
+               # Adding required arguements
+               self.p2p_connect_arguements = {'wps_method':self.wps_method,
+                       'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+
+               # Display requires a pin, and a go intent of 15
+               if (self.wps_method == 'display'):
+                       if (self.pin != None):
+                               self.p2p_connect_arguements.update({'pin':self.pin})
+                       else:
+                               print "Error:\n  Pin required for wps_method=display"
+                               usage()
+                               quit()
+
+                       if (self.go_intent != None and int(self.go_intent) != 15):
+                               print "go_intent overwritten to 15"
+
+                       self.go_intent = '15'
+
+               # Keypad requires a pin, and a go intent of less than 15
+               elif (self.wps_method == 'keypad'):
+                       if (self.pin != None):
+                               self.p2p_connect_arguements.update({'pin':self.pin})
+                       else:
+                               print "Error:\n  Pin required for wps_method=keypad"
+                               usage()
+                               quit()
+
+                       if (self.go_intent != None and int(self.go_intent) == 15):
+                               error = "Error :\n Group Owner intent cannot be" + \
+                                       " 15 for wps_method=keypad"
+                               print error
+                               usage()
+                               quit()
+
+               # Doesn't require pin
+               # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
+               elif (self.wps_method == 'pin'):
+                       if (self.pin != None):
+                               print "pin ignored"
+
+               # No pin is required for pbc so it is ignored
+               elif (self.wps_method == 'pbc'):
+                       if (self.pin != None):
+                               print "pin ignored"
+
+               else:
+                       print "Error:\n  wps_method not supported or does not exist"
+                       usage()
+                       quit()
+
+               # Go_intent is optional for all arguements
+               if (self.go_intent != None):
+                       self.p2p_connect_arguements.update(
+                               {'go_intent':dbus.Int32(self.go_intent)})
+
+       # Running p2p_connect
+       def run(self):
+               try:
+                       result_pin = self.p2p_interface.Connect(
+                               self.p2p_connect_arguements)
+
+               except dbus.DBusException, exc:
+                               raise exc
+
+               if (self.wps_method == 'pin' and \
+               not self.p2p_connect_arguements.has_key('pin') ):
+                       print "Connect return with pin value of %d " % int(result_pin)
+               gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+       # Required
+       interface_name = None
+       wps_method = None
+       addr = None
+
+       # Conditionally optional
+       pin = None
+
+       # Optional
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+       go_intent = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # WPS Method
+               elif (key == "-m"):
+                       wps_method = value
+               # Address
+               elif (key == "-a"):
+                       addr = value
+               # Pin
+               elif (key == "-p"):
+                       pin = value
+               # Group Owner Intent
+               elif (key == "-g"):
+                       go_intent = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Required Arguements check
+       if (interface_name == None or wps_method == None or addr == None):
+               print "Error:\n  Required arguements not specified"
+               usage()
+               quit()
+
+       # Group Owner Intent Check
+       if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
+               print "Error:\n  Group Owner Intent must be between 0 and 15 inclusive"
+               usage()
+               quit()
+
+       # Pin Check
+       if (pin != None and len(pin) != 8):
+               print "Error:\n  Pin is not 8 digits"
+               usage()
+               quit()
+
+       try:
+               p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface,
+                       addr,pin,wps_method,go_intent)
+
+       except:
+               print "Error:\n  Invalid Arguements"
+               usage()
+               quit()
+
+       p2p_connect_test.constructArguements()
+       p2p_connect_test.run()
+
+       os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
new file mode 100644 (file)
index 0000000..c3e39b3
--- /dev/null
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+# Tests P2P_Disconnect
+# Will perform disconnect on interface_name
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> \ " \
+               % sys.argv[0]
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i p2p-wlan0-0" % sys.argv[0]
+
+# Required Signals
+def GroupFinished(status, etc):
+       print "Disconnected"    
+       os._exit(0)
+
+class P2P_Disconnect (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global timeout
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,timeout):
+               # Initializes variables and threads
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.timeout = timeout
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               # Signals
+               self.bus.add_signal_receiver(GroupFinished,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="GroupFinished")
+
+       # Runs p2p_disconnect
+       def run(self):
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               self.p2p_interface.Disconnect()
+               gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+       timeout = 5
+       # Defaults for optional inputs
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       # Constructor
+       try:
+               p2p_disconnect_test = P2P_Disconnect(interface_name,
+                                               wpas_dbus_interface,timeout)
+
+       except:
+               print "Error:\n  Invalid wpas_dbus_interface"
+               usage()
+               quit()
+
+       # Start P2P_Disconnect
+       p2p_disconnect_test.start()
+
+       try:
+               time.sleep(int(p2p_disconnect_test.timeout))
+
+       except:
+               pass
+
+       print "Disconnect timed out"
+       quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
new file mode 100644 (file)
index 0000000..973d46a
--- /dev/null
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+# Tests p2p_find
+# Will list all devices found/lost within a time frame (timeout)
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> [-t <timeout>] \ " \
+               % sys.argv[0]
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -t = timeout = 0s (infinite)"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0 -t 10" % sys.argv[0]
+
+# Required Signals
+def deviceFound(devicepath):
+       print "Device found: %s" % (devicepath)
+
+def deviceLost(devicepath):
+       print "Device lost: %s" % (devicepath)
+
+class P2P_Find (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global timeout
+       global path
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,timeout):
+               # Initializes variables and threads
+               self.timeout = int(timeout)
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               #Adds listeners for find and lost
+               self.bus.add_signal_receiver(deviceFound,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="DeviceFound")
+               self.bus.add_signal_receiver(deviceLost,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="DeviceLost")
+
+
+               # Sets up p2p_find
+               P2PFindDict = dbus.Dictionary(
+                               {'Timeout':int(self.timeout)})
+               self.p2p_interface.Find(P2PFindDict)
+
+       # Run p2p_find
+       def run(self):
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+       # Defaults for optional inputs
+       timeout = 0
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Timeout
+               elif (key == "-t"):
+                       if ( int(value) >= 0):
+                               timeout = value
+                       else:
+                               print "Error:\n  Timeout cannot be negative"
+                               usage()
+                               quit()
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       # Constructor
+       try:
+               p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
+
+       except:
+               print "Error:\n  Invalid wpas_dbus_interface"
+               usage()
+               quit()
+
+       # Start P2P_Find
+       p2p_find_test.start()
+
+       try:
+               # If timeout is 0, then run forever
+               if (timeout == 0):
+                       while(True):
+                               pass
+               # Else sleep for (timeout)
+               else:
+                       time.sleep(p2p_find_test.timeout)
+
+       except:
+               pass
+
+       quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
new file mode 100644 (file)
index 0000000..ff8509d
--- /dev/null
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# Tests P2P_Flush
+# Will flush the p2p interface
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> \ " \
+               % sys.argv[0]
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0" % sys.argv[0]
+
+# Required Signals\
+def deviceLost(devicepath):
+       print "Device lost: %s" % (devicepath)
+
+class P2P_Flush (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global timeout
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,timeout):
+               # Initializes variables and threads
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.timeout = timeout
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               # Signals
+               self.bus.add_signal_receiver(deviceLost,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="DeviceLost")
+
+       # Runs p2p_flush
+       def run(self):
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               self.p2p_interface.Flush()
+               gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+       # Needed to show which devices were lost
+       timeout = 5
+       # Defaults for optional inputs
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       # Constructor
+       try:
+               p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
+
+       except:
+               print "Error:\n  Invalid wpas_dbus_interface"
+               usage()
+               quit()
+
+       # Start P2P_Find
+       p2p_flush_test.start()
+
+       try:
+               time.sleep(int(p2p_flush_test.timeout))
+
+       except:
+               pass
+
+       print "p2p_flush complete"
+       quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
new file mode 100644 (file)
index 0000000..5c8fdaf
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/python
+# Tests p2p_group_add
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> [-p <persistent>] \ " \
+               % sys.argv[0]
+       print "         [-f <frequency>] [-o <group_object_path>] \ "
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -p = persistant group = 0 (0=false, 1=true)"
+       print "  -f = frequency"
+       print "  -o = persistent group object path"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def GroupStarted(properties):
+       if properties.has_key("group_object"):
+               print 'Group Formation Complete %s' \
+                       % properties["group_object"]
+       os._exit(0)
+
+def WpsFailure(status, etc):
+       print "WPS Authentication Failure".format(status)
+       print etc
+       os._exit(0)
+
+class P2P_Group_Add (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global persistent
+       global frequency
+       global persistent_group_object
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Arguements
+       global P2PDictionary
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency,
+                                               persistent_group_object):
+               # Initializes variables and threads
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.persistent = persistent
+               self.frequency = frequency
+               self.persistent_group_object = persistent_group_object
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               #Adds listeners
+               self.bus.add_signal_receiver(GroupStarted,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="GroupStarted")
+               self.bus.add_signal_receiver(WpsFailure,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="WpsFailed")
+
+               # Sets up p2p_group_add dictionary
+       def constructArguements(self):
+               self.P2PDictionary = {'persistent':self.persistent}
+
+               if (self.frequency != None):
+                       if (int(self.frequency) > 0):
+                               self.P2PDictionary.update({'frequency':int(self.frequency)})
+                       else:
+                               print "Error:\n  Frequency must be greater than 0"
+                               usage()
+                               os._exit(0)
+
+               if (self.persistent_group_object != None):
+                       self.P2PDictionary.update({'persistent_group_object':
+                                               self.persistent_group_object})
+
+       # Run p2p_group_remove
+       def run(self):
+               try:
+                       self.p2p_interface.GroupAdd(self.P2PDictionary)
+
+               except:
+                       print "Error:\n  Could not preform group add"
+                       usage()
+                       os._exit(0)
+
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+       # Defaults for optional inputs
+       # 0 = false, 1 = true
+       persistent = False
+       frequency = None
+       persistent_group_object = None
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Timeout
+               elif (key == "-p"):
+                       if (value == '0'):
+                               persistent = False
+                       elif (value == '1'):
+                               persistent = True
+                       else:
+                               print "Error:\n  Persistent can only be 1 or 0"
+                               usage()
+                               os._exit(0)
+               # Frequency
+               elif (key == "-f"):
+                       frequency = value
+               # Persistent group object path
+               elif (key == "-o"):
+                       persistent_group_object = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       try:
+               p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
+                                       persistent,frequency,persistent_group_object)
+       except:
+               print "Error:\n  Invalid Arguements"
+
+       p2p_group_add_test.constructArguements()
+       p2p_group_add_test.start()
+       time.sleep(5)
+       print "Error:\n  Group formation timed out"
+       os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
new file mode 100644 (file)
index 0000000..6deb397
--- /dev/null
@@ -0,0 +1,201 @@
+#!/usr/bin/python
+# Tests p2p_invite
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> -a <addr> \ " \
+               % sys.argv[0]
+       print "         [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -a = address of peer"
+       print "  -o = persistent group object path"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+
+# Required Signals
+def InvitationResult(invite_result):
+       print "Inviation Result signal :"
+       status = invite_result['status']
+       print "status = ", status
+       if invite_result.has_key('BSSID'):
+               bssid = invite_result['BSSID']
+               print "BSSID = ", hex(bssid[0]) , ":" , \
+                hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
+                hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
+               hex(bssid[5])
+       os._exit(0)
+
+class P2P_Invite (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global addr
+       global persistent_group_object
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Arguements
+       global P2PDictionary
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,addr,
+                                               persistent_group_object):
+               # Initializes variables and threads
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.addr = addr
+               self.persistent_group_object = persistent_group_object
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               #Adds listeners
+               self.bus.add_signal_receiver(InvitationResult,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="InvitationResult")
+
+       # Sets up p2p_invite dictionary
+       def constructArguements(self):
+               self.P2PDictionary = \
+                       {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+               if (self.persistent_group_object != None):
+                       self.P2PDictionary.update({"persistent_group_object":
+                                       self.persistent_group_object})
+
+       # Run p2p_invite
+       def run(self):
+               try:
+                       self.p2p_interface.Invite(self.P2PDictionary)
+
+               except:
+                       print "Error:\n  Invalid Arguements"
+                       usage()
+                       os._exit(0)
+
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               gobject.MainLoop().run()
+
+if __name__ == "__main__":
+       # Defaults for optional inputs
+       addr = None
+       persistent_group_object = None
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               elif (key == "-a"):
+                       addr = value
+               # Persistent group object path
+               elif (key == "-o"):
+                       persistent_group_object = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       if (addr == None):
+               print "Error:\n  peer address is required"
+               usage()
+               quit()
+
+       try:
+               p2p_invite_test = \
+                       P2P_Invite(interface_name,wpas_dbus_interface,
+                                       addr,persistent_group_object)
+       except:
+               print "Error:\n  Invalid Arguements"
+               usage()
+               os._exit(1)
+
+       p2p_invite_test.constructArguements()
+       p2p_invite_test.start()
+       time.sleep(10)
+       print "Error:\n  p2p_invite timed out"
+       os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
new file mode 100644 (file)
index 0000000..bb3c1e4
--- /dev/null
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# Tests P2P_Find
+# Will listen
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> [-t <timeout>] \ " \
+               % sys.argv[0]
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -t = timeout = 0s (infinite)"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0 -t 5" % sys.argv[0]
+
+# Required Signals
+def p2pStateChange(status):
+       print status
+
+class P2P_Listen(threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global timeout
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,timeout):
+               # Initializes variables and threads
+               self.timeout = int(timeout)
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               self.bus.add_signal_receiver(p2pStateChange,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="P2PStateChanged")
+
+       # Run p2p_find
+       def run(self):
+               # Sets up p2p_listen
+               self.p2p_interface.Listen(int(self.timeout))
+
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+       # Defaults for optional inputs
+       timeout = 0
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Timeout
+               elif (key == "-t"):
+                       if ( int(value) >= 0):
+                               timeout = value
+                       else:
+                               print "Error:\n  Timeout cannot be negative"
+                               usage()
+                               quit()
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       # Constructor
+       try:
+               p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
+
+       except:
+               print "Error:\n  Invalid wpas_dbus_interface"
+               usage()
+               quit()
+
+       # Start P2P_Find
+       p2p_listen_test.start()
+
+       try:
+               # If timeout is 0, then run forever
+               if (int(p2p_listen_test.timeout) == 0):
+                       while(True):
+                               pass
+               # Else sleep for (timeout)
+               else:
+                       time.sleep(int(p2p_listen_test.timeout))
+
+       except:
+               pass
+
+       quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
new file mode 100644 (file)
index 0000000..f6c03b0
--- /dev/null
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+# Tests p2p_stop_find
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+       print "Usage:"
+       print "  %s -i <interface_name> \ " \
+               % sys.argv[0]
+       print "                 [-w <wpas_dbus_interface>]"
+       print "Options:"
+       print "  -i = interface name"
+       print "  -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+       print "Example:"
+       print "  %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def deviceLost(devicepath):
+       print "Device lost: %s" % (devicepath)
+
+def p2pStateChange(status):
+       print status
+       os._exit(0)
+
+class P2P_Stop_Find (threading.Thread):
+       # Needed Variables
+       global bus
+       global wpas_object
+       global interface_object
+       global p2p_interface
+       global interface_name
+       global wpas
+       global wpas_dbus_interface
+       global path
+       global timeout
+
+       # Dbus Paths
+       global wpas_dbus_opath
+       global wpas_dbus_interfaces_opath
+       global wpas_dbus_interfaces_interface
+       global wpas_dbus_interfaces_p2pdevice
+
+       # Constructor
+       def __init__(self,interface_name,wpas_dbus_interface,timeout):
+               # Initializes variables and threads
+               self.interface_name = interface_name
+               self.wpas_dbus_interface = wpas_dbus_interface
+               self.timeout = timeout
+
+               # Initializes thread and daemon allows for ctrl-c kill
+               threading.Thread.__init__(self)
+               self.daemon = True
+
+               # Generating interface/object paths
+               self.wpas_dbus_opath = "/" + \
+                               self.wpas_dbus_interface.replace(".","/")
+               self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+                               "/Interfaces"
+               self.wpas_dbus_interfaces_interface = \
+                               self.wpas_dbus_interface + ".Interface"
+               self.wpas_dbus_interfaces_p2pdevice = \
+                               self.wpas_dbus_interfaces_interface \
+                               + ".P2PDevice"
+
+               # Getting interfaces and objects
+               DBusGMainLoop(set_as_default=True)
+               self.bus = dbus.SystemBus()
+               self.wpas_object = self.bus.get_object(
+                               self.wpas_dbus_interface,
+                               self.wpas_dbus_opath)
+               self.wpas = dbus.Interface(self.wpas_object,
+                               self.wpas_dbus_interface)
+
+               # Try to see if supplicant knows about interface
+               # If not, throw an exception
+               try:
+                       self.path = self.wpas.GetInterface(
+                                       self.interface_name)
+               except dbus.DBusException, exc:
+                       error = 'Error:\n  Interface ' + self.interface_name \
+                               + ' was not found'
+                       print error
+                       usage()
+                       os._exit(0)
+
+               self.interface_object = self.bus.get_object(
+                               self.wpas_dbus_interface, self.path)
+               self.p2p_interface = dbus.Interface(self.interface_object,
+                               self.wpas_dbus_interfaces_p2pdevice)
+
+               # Signals
+               self.bus.add_signal_receiver(deviceLost,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="DeviceLost")
+               self.bus.add_signal_receiver(p2pStateChange,
+                       dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+                       signal_name="P2PStateChanged")
+
+       # Runs p2p_stop_find
+       def run(self):
+               # Allows other threads to keep working while MainLoop runs
+               # Required for timeout implementation
+               gobject.MainLoop().get_context().iteration(True)
+               gobject.threads_init()
+               self.p2p_interface.StopFind()
+               gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+       # Needed because P2PStateChanged signal is not caught
+       timeout = 5
+       # Defaults for optional inputs
+       wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+       # interface_name is required
+       interface_name = None
+
+       # Using getopts to handle options
+       try:
+               options, args = getopt.getopt(sys.argv[1:],"ht:i:w:")
+
+       except getopt.GetoptError:
+               usage()
+               quit()
+
+       # If theres a switch, override default option
+       for key, value in options:
+               # Help
+               if (key == "-h"):
+                       usage()
+                       quit()
+               # Interface Name
+               elif (key == "-i"):
+                       interface_name = value
+               # Dbus interface
+               elif (key == "-w"):
+                       wpas_dbus_interface = value
+               else:
+                       assert False, "unhandled option"
+
+       # Interface name is required and was not given
+       if (interface_name == None):
+               print "Error:\n  interface_name is required"
+               usage()
+               quit()
+
+       # Constructor
+       try:
+               p2p_stop_find_test = P2P_Stop_Find(interface_name,
+                                               wpas_dbus_interface,timeout)
+
+       except:
+               print "Error:\n  Invalid wpas_dbus_interface"
+               usage()
+               quit()
+
+       # Start P2P_Find
+       p2p_stop_find_test.start()
+
+       try:
+               time.sleep(int(p2p_stop_find_test.timeout))
+
+       except:
+               pass
+
+       print "p2p find stopped"
+       quit()
index b040e0a..d90ef18 100755 (executable)
@@ -59,12 +59,12 @@ def showBss(bss):
                          dbus_interface=dbus.PROPERTIES_IFACE)
        ssid = byte_array_to_string(val)
 
-       val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPAIE',
+       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, 'RSNIE',
+       val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN',
                          dbus_interface=dbus.PROPERTIES_IFACE)
        wpa2 = "no"
        if val != None:
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
new file mode 100755 (executable)
index 0000000..d6dec85
--- /dev/null
@@ -0,0 +1,441 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@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 random
+import StringIO
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+logging.basicConfig()
+
+import wpaspy
+
+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 = wpaspy.Ctrl(ctrl)
+            return wpas
+        except Exception, e:
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return False
+    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")):
+        return False
+    return True
+
+def wpas_get_config_token(id=None):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    if id:
+        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
+    else:
+        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
+
+
+def wpas_get_er_config_token(uuid):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_req():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel(uuid):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    if uuid is None:
+        return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+    return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
+                        str(req).encode("hex") + " " +
+                        str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+    def __init__(self):
+        super(HandoverServer, self).__init__()
+
+    def process_request(self, request):
+        print "HandoverServer - request received"
+        print "Parsed handover request: " + request.pretty()
+
+        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+        for carrier in request.carriers:
+            print "Remote carrier type: " + carrier.type
+            if carrier.type == "application/vnd.wfa.wsc":
+                print "WPS carrier type match - add WPS carrier record"
+                self.received_carrier = carrier.record
+                data = wpas_get_handover_sel(self.uuid)
+                if data is None:
+                    print "Could not get handover select carrier record from wpa_supplicant"
+                    continue
+                print "Handover select carrier record from wpa_supplicant:"
+                print data.encode("hex")
+                self.sent_carrier = data
+
+                message = nfc.ndef.Message(data);
+                sel.add_carrier(message[0], "active", message[1:])
+
+        print "Handover select:"
+        print sel.pretty()
+        print str(sel).encode("hex")
+
+        print "Sending handover select"
+        return sel
+
+
+def wps_handover_resp(peer, uuid):
+    if uuid is None:
+        print "Trying to handle WPS handover"
+    else:
+        print "Trying to handle WPS handover with AP " + uuid
+
+    srv = HandoverServer()
+    srv.sent_carrier = None
+    srv.uuid = uuid
+
+    nfc.llcp.activate(peer);
+
+    try:
+        print "Trying handover";
+        srv.start()
+        print "Wait for disconnect"
+        while nfc.llcp.connected():
+            time.sleep(0.1)
+        print "Disconnected after handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        return
+
+    if srv.sent_carrier:
+        wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    print "Done with handover"
+    time.sleep(1)
+
+
+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 carrier record from wpa_supplicant"
+        return
+    print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+    record = nfc.ndef.Record()
+    f = StringIO.StringIO(data)
+    record._read(f)
+    record = nfc.ndef.HandoverCarrierRecord(record)
+    print "Parsed handover request carrier record:"
+    print record.pretty()
+
+    message = nfc.ndef.HandoverRequestMessage(version="1.2")
+    message.nonce = random.randint(0, 0xffff)
+    message.add_carrier(record, "active")
+
+    print "Handover request:"
+    print message.pretty()
+
+    nfc.llcp.activate(peer);
+
+    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()
+    if message is None:
+        print "No response received"
+        nfc.llcp.shutdown()
+        client.close()
+        return
+    if message.type != "urn:nfc:wkt:Hs":
+        print "Response was not Hs - received: " + message.type
+        nfc.llcp.shutdown()
+        client.close()
+        return
+
+    print "Received message"
+    print message.pretty()
+    message = nfc.ndef.HandoverSelectMessage(message)
+    print "Handover select received"
+    print message.pretty()
+
+    for carrier in message.carriers:
+        print "Remote carrier type: " + carrier.type
+        if carrier.type == "application/vnd.wfa.wsc":
+            print "WPS carrier type match - send to wpa_supplicant"
+            wpas_report_handover(data, carrier.record, "INIT")
+            wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+            print wifi.pretty()
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    client.close()
+    print "Done with handover"
+
+
+def wps_tag_read(tag, wait_remove=True):
+    success = False
+    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"
+                success = wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    if wait_remove:
+        print "Remove tag"
+        while tag.is_present:
+            time.sleep(0.1)
+
+    return success
+
+
+def wps_write_config_tag(clf, id=None, wait_remove=True):
+    print "Write WPS config token"
+    data = wpas_get_config_token(id)
+    if (data == None):
+        print "Could not get WPS config token from wpa_supplicant"
+        sys.exit(1)
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while wait_remove and tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_er_config_tag(clf, uuid):
+    print "Write WPS ER config token"
+    data = wpas_get_er_config_token(uuid)
+    if (data == None):
+        print "Could not get WPS config token from wpa_supplicant"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_password_tag(clf, wait_remove=True):
+    print "Write WPS password token"
+    data = wpas_get_password_token()
+    if (data == None):
+        print "Could not get WPS password token from wpa_supplicant"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while wait_remove and tag.is_present:
+        time.sleep(0.1)
+
+
+def find_peer(clf):
+    while True:
+        if nfc.llcp.connected():
+            print "LLCP connected"
+        general_bytes = nfc.llcp.startup({})
+        peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "listen -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        peer = clf.poll(general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "poll -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        if peer:
+            print "Found tag"
+            return peer
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        arg_uuid = None
+        if len(sys.argv) > 1 and sys.argv[1] != '-1':
+            arg_uuid = sys.argv[1]
+
+        if len(sys.argv) > 1 and sys.argv[1] == '-1':
+            only_one = True
+        else:
+            only_one = False
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+            wps_write_config_tag(clf)
+            raise SystemExit
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-config-no-wait":
+            wps_write_config_tag(clf, wait_remove=False)
+            raise SystemExit
+
+        if len(sys.argv) > 2 and sys.argv[1] == "write-config-id":
+            wps_write_config_tag(clf, sys.argv[2])
+            raise SystemExit
+
+        if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
+            wps_write_er_config_tag(clf, sys.argv[2])
+            raise SystemExit
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+            wps_write_password_tag(clf)
+            raise SystemExit
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-password-no-wait":
+            wps_write_password_tag(clf, wait_remove=False)
+            raise SystemExit
+
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            tag = find_peer(clf)
+            if isinstance(tag, nfc.DEP):
+                if arg_uuid is None:
+                    wps_handover_init(tag)
+                elif arg_uuid is "ap":
+                    wps_handover_resp(tag, None)
+                else:
+                    wps_handover_resp(tag, arg_uuid)
+                if only_one:
+                    break
+                continue
+
+            if tag.ndef:
+                success = wps_tag_read(tag, not only_one)
+                if only_one:
+                    if not success:
+                        sys.exit(1)
+                    break
+                continue
+
+            print "Not an NDEF tag - remove tag"
+            if only_one:
+                sys.exit(1)
+            while tag.is_present:
+                time.sleep(0.1)
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
index 3b736da..06a97d3 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2009, Atheros Communications
  * Copyright (c) 2011, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "gas_query.h"
 
 
-#define GAS_QUERY_TIMEOUT 5
+/** GAS query timeout in seconds */
+#define GAS_QUERY_TIMEOUT_PERIOD 2
 
 
+/**
+ * struct gas_query_pending - Pending GAS query
+ */
 struct gas_query_pending {
        struct dl_list list;
        u8 addr[ETH_ALEN];
@@ -46,6 +44,9 @@ struct gas_query_pending {
        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 */
@@ -56,6 +57,11 @@ 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;
@@ -88,6 +94,10 @@ static void gas_query_done(struct gas_query *gas,
 }
 
 
+/**
+ * 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;
@@ -261,6 +271,11 @@ static void gas_query_rx_comeback(struct gas_query *gas,
        if (frag_id != query->next_frag_id) {
                wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
                           "from " MACSTR, MAC2STR(query->addr));
+               if (frag_id + 1 == query->next_frag_id) {
+                       wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
+                                  "retry of previous fragment");
+                       return;
+               }
                gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
                return;
        }
@@ -280,6 +295,17 @@ static void gas_query_rx_comeback(struct gas_query *gas,
 }
 
 
+/**
+ * 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)
 {
@@ -420,6 +446,16 @@ static int gas_query_dialog_token_available(struct gas_query *gas,
 }
 
 
+/**
+ * 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,
@@ -430,16 +466,20 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
 {
        struct gas_query_pending *query;
        int dialog_token;
+       static int next_start = 0;
 
        if (wpabuf_len(req) < 3)
                return -1;
 
        for (dialog_token = 0; dialog_token < 256; dialog_token++) {
-               if (gas_query_dialog_token_available(gas, dst, dialog_token))
+               if (gas_query_dialog_token_available(
+                           gas, dst, (next_start + dialog_token) % 256))
                        break;
        }
        if (dialog_token == 256)
                return -1; /* Too many pending queries */
+       dialog_token = (next_start + dialog_token) % 256;
+       next_start = (dialog_token + 1) % 256;
 
        query = os_zalloc(sizeof(*query));
        if (query == NULL)
@@ -459,17 +499,24 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
        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, 0, gas_query_timeout,
+       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;
index 64c3825..5c3d161 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2009, Atheros Communications
  * Copyright (c) 2011, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef GAS_QUERY_H
@@ -25,6 +19,9 @@ 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,
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
new file mode 100644 (file)
index 0000000..4048cf7
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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 */
+}
+
+
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+                   struct wpa_bss *bss)
+{
+       if (!wpa_s->conf->hs20 || !ssid)
+               return 0;
+
+       if (ssid->parent_cred)
+               return 1;
+
+       if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE))
+               return 0;
+
+       /*
+        * This may catch some non-Hotspot 2.0 cases, but it is safer to do that
+        * than cause Hotspot 2.0 connections without indication element getting
+        * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element.
+        */
+
+       if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X))
+               return 0;
+       if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP))
+               return 0;
+       if (ssid->proto != WPA_PROTO_RSN)
+               return 0;
+
+       return 1;
+}
+
+
+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;
+       }
+}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
new file mode 100644 (file)
index 0000000..1c8481b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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);
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+                   struct wpa_bss *bss);
+
+#endif /* HS20_SUPPLICANT_H */
index d4fa39d..687c042 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - IBSS RSN
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.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);
@@ -290,6 +296,13 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 }
 
 
+static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
+{
+       struct ibss_rsn *ibss_rsn = ctx;
+       wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
+}
+
+
 static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
                                                  void *ctx),
                             void *cb_ctx)
@@ -308,6 +321,53 @@ static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
 }
 
 
+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)
 {
@@ -328,10 +388,12 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
        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;
+       cb.disconnect = ibss_rsn_disconnect;
 
        ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
        if (ibss_rsn->auth_group == NULL) {
@@ -383,13 +445,11 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
        if (ibss_rsn == NULL)
                return -1;
 
-       for (peer = ibss_rsn->peers; peer; peer = peer->next) {
-               if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) {
-                       wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and "
-                                  "Supplicant for peer " MACSTR " already "
-                                  "running", MAC2STR(addr));
-                       return 0;
-               }
+       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 "
@@ -577,11 +637,9 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
        if (ibss_rsn == NULL)
                return -1;
 
-       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);
-       }
+       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) {
                /*
index dbc889f..1da94ab 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - IBSS RSN
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IBSS_RSN_H
index d42aa40..2f35240 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros, 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "common/ieee802_11_defs.h"
 #include "common/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"
 
 
 #endif
 
 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+
+
+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_supplicant_fast_associate(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,
@@ -85,29 +105,135 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
 }
 
 
+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[] = {
-               ANQP_CAPABILITY_LIST,
-               ANQP_VENUE_NAME,
-               ANQP_NETWORK_AUTH_TYPE,
-               ANQP_ROAMING_CONSORTIUM,
-               ANQP_IP_ADDR_TYPE_AVAILABILITY,
-               ANQP_NAI_REALM,
-               ANQP_3GPP_CELLULAR_NETWORK,
-               ANQP_DOMAIN_NAME
-       };
+       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));
+       wpa_s->interworking_gas_bss = bss;
 
-       buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
-                            extra);
+       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;
@@ -117,6 +243,8 @@ static int interworking_anqp_send_req(struct wpa_supplicant *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);
@@ -280,11 +408,9 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
                return NULL;
        }
        wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
-       r->realm = os_malloc(realm_len + 1);
+       r->realm = dup_binstr(pos, realm_len);
        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) {
@@ -297,7 +423,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
                wpa_printf(MSG_DEBUG, "No room for EAP Methods");
                return NULL;
        }
-       r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+       r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
        if (r->eap == NULL)
                return NULL;
 
@@ -333,7 +459,7 @@ static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
                return NULL;
        }
 
-       realm = os_zalloc(num * sizeof(struct nai_realm));
+       realm = os_calloc(num, sizeof(struct nai_realm));
        if (realm == NULL)
                return NULL;
 
@@ -395,13 +521,18 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
                return 0;
        }
 
-       if (eap->method == EAP_TYPE_PEAP &&
-           eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
-               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 0;
+                       return 1; /* Assume TTLS/MSCHAPv2 is used */
                if (eap->inner_method &&
                    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
                        return 0;
@@ -422,20 +553,41 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
 }
 
 
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+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 (wpa_s->conf->home_username == NULL ||
-           wpa_s->conf->home_username[0] == '\0' ||
-           wpa_s->conf->home_password == NULL ||
-           wpa_s->conf->home_password[0] == '\0')
+       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 (nai_realm_cred_username(eap))
+               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;
        }
 
@@ -445,21 +597,17 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
 
 #ifdef INTERWORKING_3GPP
 
-static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
 {
-       const char *sep;
        u8 plmn[3];
        const u8 *pos, *end;
        u8 udhl;
 
-       sep = os_strchr(imsi, '-');
-       if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
-               return 0;
-
        /* 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';
-       if (sep - imsi == 6)
+       /* default to MNC length 3 if unknown */
+       if (mnc_len != 2)
                plmn[1] |= (imsi[5] - '0') << 4;
        else
                plmn[1] |= 0xf0;
@@ -501,6 +649,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
                                        break;
                                if (os_memcmp(pos, plmn, 3) == 0)
                                        return 1; /* Found matching PLMN */
+                               pos += 3;
                        }
                }
 
@@ -511,10 +660,11 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
 }
 
 
-static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+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 nai[100], *end, *pos;
+       char *end, *pos;
        size_t msin_len, plmn_len;
 
        /*
@@ -529,17 +679,22 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
                return -1;
        }
        sep = os_strchr(imsi, '-');
-       if (sep == NULL)
+       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;
-       plmn_len = sep - imsi;
        if (plmn_len != 5 && plmn_len != 6)
                return -1;
-       msin = sep + 1;
        msin_len = os_strlen(msin);
 
        pos = nai;
-       end = pos + sizeof(nai);
-       *pos++ = prefix;
+       end = nai + nai_len;
+       if (prefix)
+               *pos++ = prefix;
        os_memcpy(pos, imsi, plmn_len);
        pos += plmn_len;
        os_memcpy(pos, msin, msin_len);
@@ -557,18 +712,49 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
        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_cred *cred,
                                     struct wpa_bss *bss)
 {
 #ifdef INTERWORKING_3GPP
        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;
 
        ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
        if (ie == NULL)
@@ -579,9 +765,11 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        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)
@@ -589,32 +777,66 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        os_memcpy(ssid->ssid, ie + 2, ie[1]);
        ssid->ssid_len = ie[1];
 
-       /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
-       if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
-               wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
+       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 (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
+
+       if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
                wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
                goto fail;
        }
 
-       if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
+       if (cred->milenage && cred->milenage[0]) {
                if (wpa_config_set_quoted(ssid, "password",
-                                         wpa_s->conf->home_milenage) < 0)
+                                         cred->milenage) < 0)
                        goto fail;
-       } else {
-               /* TODO: PIN */
+       } 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 (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
-           wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
-           < 0)
+       if (cred->password && cred->password[0] &&
+           wpa_config_set_quoted(ssid, "password", cred->password) < 0)
                goto fail;
 
-       wpa_supplicant_select_network(wpa_s, ssid);
+       wpa_config_update_prio_list(wpa_s->conf);
+       interworking_reconnect(wpa_s);
 
        return 0;
 
@@ -626,8 +848,295 @@ fail:
 }
 
 
+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, *cred_rc, *cred_3gpp;
        struct wpa_ssid *ssid;
        struct nai_realm *realm;
        struct nai_realm_eap *eap = NULL;
@@ -635,7 +1144,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        char buf[100];
        const u8 *ie;
 
-       if (bss == NULL)
+       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) {
@@ -644,28 +1153,71 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                return -1;
        }
 
-       realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+       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_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+                                                                       bss);
+       if (cred_rc) {
+               wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+                          "consortium matching credential priority %d",
+                          cred_rc->priority);
+       }
+
+       cred = interworking_credentials_available_realm(wpa_s, bss);
+       if (cred) {
+               wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+                          "matching credential priority %d",
+                          cred->priority);
+       }
+
+       cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+       if (cred_3gpp) {
+               wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+                          "credential priority %d", cred_3gpp->priority);
+       }
+
+       if (cred_rc &&
+           (cred == NULL || cred_rc->priority >= cred->priority) &&
+           (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+               return interworking_connect_roaming_consortium(wpa_s, cred_rc,
+                                                              bss, ie);
+
+       if (cred_3gpp &&
+           (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+               return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+       }
+
+       if (cred == NULL) {
+               wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+                          "found for " MACSTR, MAC2STR(bss->bssid));
+               return -1;
+       }
+
+       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;
+               return -1;
        }
 
        for (i = 0; i < count; i++) {
-               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+               if (!nai_realm_match(&realm[i], cred->realm))
                        continue;
-               eap = nai_realm_find_eap(wpa_s, &realm[i]);
+               eap = nai_realm_find_eap(cred, &realm[i]);
                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));
@@ -681,8 +1233,10 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                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)
@@ -690,18 +1244,11 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        os_memcpy(ssid->ssid, ie + 2, ie[1]);
        ssid->ssid_len = ie[1];
 
-       if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
-                                                    eap->method), 0) < 0)
-               goto fail;
-
-       if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
-           wpa_config_set_quoted(ssid, "identity",
-                                 wpa_s->conf->home_username) < 0)
+       if (interworking_set_hs20_params(wpa_s, ssid) < 0)
                goto fail;
 
-       if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
-           wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
-           < 0)
+       if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
+                                                    eap->method), 0) < 0)
                goto fail;
 
        switch (eap->method) {
@@ -726,8 +1273,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                                goto fail;
                        break;
                case NAI_REALM_INNER_NON_EAP_MSCHAP:
-                       if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
-                           < 0)
+                       if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
+                                          0) < 0)
                                goto fail;
                        break;
                case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
@@ -735,24 +1282,35 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                                           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_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 (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
-           wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
-           0)
+       if (interworking_set_eap_params(ssid, cred,
+                                       eap->method == EAP_TYPE_TTLS) < 0)
                goto fail;
 
        nai_realm_free(realm, count);
 
-       wpa_supplicant_select_network(wpa_s, ssid);
+       wpa_config_update_prio_list(wpa_s->conf);
+       interworking_reconnect(wpa_s);
 
        return 0;
 
@@ -764,92 +1322,333 @@ fail:
 }
 
 
-static int interworking_credentials_available_3gpp(
+static struct wpa_cred * interworking_credentials_available_3gpp(
        struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-       int ret = 0;
-
+       struct wpa_cred *selected = NULL;
 #ifdef INTERWORKING_3GPP
-       if (bss->anqp_3gpp == NULL)
-               return ret;
+       struct wpa_cred *cred;
+       int ret;
 
-       if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
-           wpa_s->conf->home_milenage == NULL ||
-           !wpa_s->conf->home_milenage[0])
-               return ret;
+       if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+               return NULL;
 
-       wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
-                  MAC2STR(bss->bssid));
-       ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
-       wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+       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 */
+#ifdef CONFIG_EAP_PROXY
+               if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+                       imsi = wpa_s->imsi;
+                       mnc_len = wpa_s->mnc_len;
+                       goto compare;
+               }
+#endif /* CONFIG_EAP_PROXY */
+
+               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;
+
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
+       compare:
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
+               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 ret;
+       return selected;
 }
 
 
-static int interworking_credentials_available_realm(
+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;
-       int found = 0;
 
-       if (bss->anqp_nai_realm == NULL)
-               return 0;
+       if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
+               return NULL;
 
-       if (wpa_s->conf->home_realm == NULL)
-               return 0;
+       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);
+       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 0;
+               return NULL;
        }
 
-       for (i = 0; i < count; i++) {
-               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->realm == NULL)
                        continue;
-               if (nai_realm_find_eap(wpa_s, &realm[i])) {
-                       found++;
-                       break;
+
+               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 found;
+       return selected;
 }
 
 
-static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
-                                             struct wpa_bss *bss)
+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)
 {
-       return interworking_credentials_available_realm(wpa_s, bss) ||
-               interworking_credentials_available_3gpp(wpa_s, bss);
+#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;
+       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) {
-               if (!interworking_credentials_available(wpa_s, bss))
+               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++;
-               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
-                       MAC2STR(bss->bssid));
-               if (selected == NULL && wpa_s->auto_select)
-                       selected = bss;
+               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");
        }
@@ -859,13 +1658,50 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
 }
 
 
+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 (!wpa_s->fetch_anqp_in_progress)
+       if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
                return;
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
@@ -876,6 +1712,17 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
                        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 "
@@ -894,7 +1741,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
 }
 
 
-static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
 {
        struct wpa_bss *bss;
 
@@ -912,6 +1759,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
                return 0;
 
        wpa_s->network_select = 0;
+       wpa_s->fetch_all_anqp = 1;
 
        interworking_start_fetch_anqp(wpa_s);
 
@@ -939,8 +1787,10 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
 
        freq = wpa_s->assoc_freq;
        bss = wpa_bss_get_bssid(wpa_s, dst);
-       if (bss)
+       if (bss) {
+               wpa_bss_anqp_unshare_alloc(bss);
                freq = bss->freq;
+       }
        if (freq <= 0)
                return -1;
 
@@ -965,11 +1815,18 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
 
 
 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
-                                           const u8 *sa, u16 info_id,
+                                           struct wpa_bss *bss, 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:
@@ -980,9 +1837,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
                        " Venue Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_venue_name);
-                       bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->venue_name);
+                       anqp->venue_name = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_NETWORK_AUTH_TYPE:
@@ -991,10 +1848,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
                                  "Type", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_network_auth_type);
-                       bss->anqp_network_auth_type =
-                               wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->network_auth_type);
+                       anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_ROAMING_CONSORTIUM:
@@ -1002,10 +1858,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        " Roaming Consortium list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
                                  pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_roaming_consortium);
-                       bss->anqp_roaming_consortium =
-                               wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->roaming_consortium);
+                       anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@@ -1014,9 +1869,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        MAC2STR(sa));
                wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
                            pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_ip_addr_type_availability);
-                       bss->anqp_ip_addr_type_availability =
+               if (anqp) {
+                       wpabuf_free(anqp->ip_addr_type_availability);
+                       anqp->ip_addr_type_availability =
                                wpabuf_alloc_copy(pos, slen);
                }
                break;
@@ -1024,9 +1879,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                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 (bss) {
-                       wpabuf_free(bss->anqp_nai_realm);
-                       bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->nai_realm);
+                       anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_3GPP_CELLULAR_NETWORK:
@@ -1034,18 +1889,18 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        " 3GPP Cellular Network information", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
                                  pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_3gpp);
-                       bss->anqp_3gpp = wpabuf_alloc_copy(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 (bss) {
-                       wpabuf_free(bss->anqp_domain_name);
-                       bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->domain_name);
+                       anqp->domain_name = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_VENDOR_SPECIFIC:
@@ -1053,6 +1908,28 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        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",
@@ -1078,6 +1955,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
        const u8 *end;
        u16 info_id;
        u16 slen;
+       struct wpa_bss *bss = NULL, *tmp;
 
        if (result != GAS_QUERY_SUCCESS)
                return;
@@ -1090,6 +1968,21 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
                return;
        }
 
+       /*
+        * If possible, select the BSS entry based on which BSS entry was used
+        * for the request. This can help in cases where multiple BSS entries
+        * may exist for the same AP.
+        */
+       dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+               if (tmp == wpa_s->interworking_gas_bss &&
+                   os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+                       bss = tmp;
+                       break;
+               }
+       }
+       if (bss == NULL)
+               bss = wpa_bss_get_bssid(wpa_s, dst);
+
        pos = wpabuf_head(resp);
        end = pos + wpabuf_len(resp);
 
@@ -1107,7 +2000,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
                                   "for Info ID %u", info_id);
                        break;
                }
-               interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+               interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
                                                slen);
                pos += slen;
        }
@@ -1127,12 +2020,95 @@ 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 = 2;
+       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;
+}
index 247df30..4a4af82 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef INTERWORKING_H
@@ -23,9 +17,16 @@ 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 */
index e196f3c..39b837e 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -20,6 +14,7 @@
 #include "common.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "p2p_supplicant.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -31,6 +26,7 @@ static void usage(void)
               "usage:\n"
               "  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
               "[-g<global ctrl>] \\\n"
+              "        [-G<group>] \\\n"
               "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
               "[-p<driver_param>] \\\n"
               "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
@@ -38,7 +34,8 @@ static void usage(void)
               "        [-o<override driver>] [-O<override ctrl>] \\\n"
               "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
               "[-D<driver>] \\\n"
-              "        [-p<driver_param>] [-b<br_ifname>] ...]\n"
+              "        [-p<driver_param>] [-b<br_ifname>] [-I<config file>] "
+              "...]\n"
               "\n"
               "drivers:\n",
               wpa_supplicant_version, wpa_supplicant_license);
@@ -56,6 +53,7 @@ static void usage(void)
               "  -c = Configuration file\n"
               "  -C = ctrl_interface parameter (only used if -c is not)\n"
               "  -i = interface name\n"
+              "  -I = additional configuration file\n"
               "  -d = increase debugging verbosity (-dd even more)\n"
               "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
               "  -e = entropy file\n");
@@ -63,13 +61,18 @@ static void usage(void)
        printf("  -f = log output to debug file instead of stdout\n");
 #endif /* CONFIG_DEBUG_FILE */
        printf("  -g = global ctrl_interface\n"
+              "  -G = global ctrl_interface group\n"
               "  -K = include keys (passwords, etc.) in debug output\n");
 #ifdef CONFIG_DEBUG_SYSLOG
        printf("  -s = log output to syslog instead of stdout\n");
 #endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       printf("  -T = record to Linux tracing in addition to logging\n");
+       printf("       (records all messages regardless of debug verbosity)\n");
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
        printf("  -t = include timestamp in debug messages\n"
               "  -h = show this help text\n"
-              "  -L = show license (GPL and BSD)\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"
@@ -84,7 +87,7 @@ static void usage(void)
 
        printf("example:\n"
               "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
-              wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+              wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211");
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 }
 
@@ -103,20 +106,31 @@ static void license(void)
 }
 
 
-static void wpa_supplicant_fd_workaround(void)
+static void wpa_supplicant_fd_workaround(int start)
 {
 #ifdef __linux__
-       int s, i;
+       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. */
-       for (i = 0; i < 3; i++) {
-               s = open("/dev/null", O_RDWR);
-               if (s > 2) {
-                       close(s);
-                       break;
+       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__ */
@@ -142,10 +156,11 @@ int main(int argc, char *argv[])
                return -1;
        iface_count = 1;
 
-       wpa_supplicant_fd_workaround();
+       wpa_supplicant_fd_workaround(1);
 
        for (;;) {
-               c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
+               c = getopt(argc, argv,
+                          "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW");
                if (c < 0)
                        break;
                switch (c) {
@@ -185,6 +200,9 @@ int main(int argc, char *argv[])
                case 'g':
                        params.ctrl_interface = optarg;
                        break;
+               case 'G':
+                       params.ctrl_interface_group = optarg;
+                       break;
                case 'h':
                        usage();
                        exitcode = 0;
@@ -192,6 +210,9 @@ int main(int argc, char *argv[])
                case 'i':
                        iface->ifname = optarg;
                        break;
+               case 'I':
+                       iface->confanother = optarg;
+                       break;
                case 'K':
                        params.wpa_debug_show_keys++;
                        break;
@@ -220,6 +241,11 @@ int main(int argc, char *argv[])
                        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;
@@ -237,8 +263,8 @@ int main(int argc, char *argv[])
                        break;
                case 'N':
                        iface_count++;
-                       iface = os_realloc(ifaces, iface_count *
-                                          sizeof(struct wpa_interface));
+                       iface = os_realloc_array(ifaces, iface_count,
+                                                sizeof(struct wpa_interface));
                        if (iface == NULL)
                                goto out;
                        ifaces = iface;
@@ -258,9 +284,14 @@ int main(int argc, char *argv[])
                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++) {
+               struct wpa_supplicant *wpa_s;
+
                if ((ifaces[i].confname == NULL &&
                     ifaces[i].ctrl_interface == NULL) ||
                    ifaces[i].ifname == NULL) {
@@ -271,8 +302,18 @@ int main(int argc, char *argv[])
                        exitcode = -1;
                        break;
                }
-               if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+               wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+               if (wpa_s == NULL) {
+                       exitcode = -1;
+                       break;
+               }
+#ifdef CONFIG_P2P
+               if (wpa_s->global->p2p == NULL &&
+                   (wpa_s->drv_flags &
+                    WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+                   wpas_p2p_add_p2pdev_interface(wpa_s) < 0)
                        exitcode = -1;
+#endif /* CONFIG_P2P */
        }
 
        if (exitcode == 0)
@@ -281,6 +322,7 @@ int main(int argc, char *argv[])
        wpa_supplicant_deinit(global);
 
 out:
+       wpa_supplicant_fd_workaround(0);
        os_free(ifaces);
        os_free(params.pid_file);
 
index 993338a..010c30a 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / Example program entrypoint
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp
deleted file mode 100644 (file)
index 4ff364b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * WPA Supplicant / Program entrypoint for Symbian
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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;
-}
index 19d9950..93a68f1 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / WinMain() function for Windows-based applications
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 4a46ed5..0b7d5ce 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / main() function for Win32 service
  * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
diff --git a/wpa_supplicant/nfc_pw_token.c b/wpa_supplicant/nfc_pw_token.c
new file mode 100644 (file)
index 0000000..11afb5b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * nfc_pw_token - Tool for building NFC password tokens for WPS
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "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;
+}
index 71778ae..35a029f 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Event notifications
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -88,7 +82,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_P2P
        if (new_state == WPA_COMPLETED)
                wpas_p2p_notif_connected(wpa_s);
-       else if (new_state < WPA_ASSOCIATED)
+       else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
                wpas_p2p_notif_disconnected(wpa_s);
 #endif /* CONFIG_P2P */
 
@@ -103,6 +97,12 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 }
 
 
+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);
@@ -323,6 +323,9 @@ void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
 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 */
 }
 
 
@@ -525,9 +528,12 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 
 
 static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
-                                         const u8 *sta)
+                                         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
@@ -541,6 +547,9 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
         */
        wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+       /* Notify listeners a new station has been authorized */
+       wpas_dbus_signal_sta_authorized(wpa_s, sta);
 }
 
 
@@ -560,14 +569,18 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
         */
        wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+       /* Notify listeners a station has been deauthorized */
+       wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
 }
 
 
 void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
-                               const u8 *mac_addr, int authorized)
+                               const u8 *mac_addr, int authorized,
+                               const u8 *p2p_dev_addr)
 {
        if (authorized)
-               wpas_notify_ap_sta_authorized(wpa_s, mac_addr);
+               wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
        else
                wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
 }
@@ -604,3 +617,23 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
        /* 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);
+       wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_STATUS
+                    "status='%s' parameter='%s'",
+                    status, parameter);
+}
index 7d4a11e..58675ac 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - Event notifications
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef NOTIFY_H
@@ -28,6 +22,7 @@ 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);
@@ -86,7 +81,8 @@ 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 *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,
@@ -126,5 +122,10 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 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 */
index 790f14a..856eca7 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2009-2010, Atheros Communications
  * Copyright (c) 2011, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -138,6 +132,17 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+/**
+ * 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)
@@ -170,6 +175,27 @@ void offchannel_send_action_tx_status(
 }
 
 
+/**
+ * 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,
@@ -272,6 +298,13 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
 }
 
 
+/**
+ * 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 "
@@ -290,6 +323,15 @@ void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
 }
 
 
+/**
+ * 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)
 {
@@ -299,6 +341,14 @@ void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 }
 
 
+/**
+ * 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)
 {
@@ -306,9 +356,42 @@ void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 }
 
 
-void offchannel_deinit(struct wpa_supplicant *wpa_s)
+/**
+ * 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);
 }
index 60e0d03..0ad7e18 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2009-2010, Atheros Communications
  * Copyright (c) 2011, Qualcomm Atheros
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef OFFCHANNEL_H
@@ -35,5 +29,7 @@ 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 */
index 7cf37d0..c817947 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - P2P
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -37,7 +31,9 @@
 #include "offchannel.h"
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
-
+#ifdef TIZEN_EXT_BUSY_DEVICE
+#include "p2p/p2p_i.h"
+#endif
 
 /*
  * How many times to try to scan to find the GO before giving up on join
@@ -45,6 +41,8 @@
  */
 #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
 #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 */
+
+#define P2P_MGMT_DEVICE_PREFIX         "p2p-dev-"
+
+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);
+                        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_group_formation_timeout(void *eloop_ctx,
+                                            void *timeout_ctx);
+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_set_own_freq_preference(struct wpa_supplicant *wpa_s,
+                                            int freq)
+{
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       if (freq > 0 &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+           wpa_s->parent->conf->p2p_ignore_shared_freq)
+               freq = 0;
+       p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
+}
 
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -81,8 +123,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 
        for (i = 0; i < scan_res->num; i++) {
                struct wpa_scan_res *bss = scan_res->res[i];
+               struct os_time time_tmp_age, entry_ts;
+               time_tmp_age.sec = bss->age / 1000;
+               time_tmp_age.usec = (bss->age % 1000) * 1000;
+               os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
                if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
-                                        bss->freq, bss->level,
+                                        bss->freq, &entry_ts, bss->level,
                                         (const u8 *) (bss + 1),
                                         bss->ie_len) > 0)
                        break;
@@ -94,19 +140,32 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                         unsigned int num_req_dev_types,
-                        const u8 *req_dev_types)
+                        const u8 *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;
-       int was_in_p2p_scan;
 
        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_scan_scheduled(ifs) || ifs->scanning) &&
+                   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 */
@@ -115,8 +174,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE,
+       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;
@@ -130,7 +189,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        wpabuf_put_buf(ies, wps_ie);
        wpabuf_free(wps_ie);
 
-       p2p_scan_ie(wpa_s->global->p2p, ies);
+       p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
 
        params.p2p_probe = 1;
        params.extra_ies = wpabuf_head(ies);
@@ -142,29 +201,28 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                break;
        case P2P_SCAN_FULL:
                break;
-       case P2P_SCAN_SPECIFIC:
-               social_channels[0] = freq;
-               social_channels[1] = 0;
-               params.freqs = social_channels;
-               break;
        case P2P_SCAN_SOCIAL_PLUS_ONE:
                social_channels[3] = freq;
                params.freqs = social_channels;
                break;
        }
 
-       was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
-       wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
        ret = wpa_drv_scan(wpa_s, &params);
 
        wpabuf_free(ies);
 
        if (ret) {
-               wpa_s->scan_res_handler = NULL;
-               if (wpa_s->scanning || was_in_p2p_scan) {
-                       wpa_s->p2p_cb_on_scan_complete = 1;
-                       ret = 1;
+               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 {
+               os_get_time(&wpa_s->scan_trigger_time);
+               wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
        }
 
        return ret;
@@ -211,28 +269,33 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+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;
 
-       eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
-
        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.
+                * 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->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
-                            (ssid->key_mgmt & WPA_KEY_MGMT_WPS)))
+                       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";
@@ -247,30 +310,54 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                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);
+               wpa_msg_global(wpa_s->parent, MSG_INFO,
+                              P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                              wpa_s->ifname, wpa_s->cross_connect_uplink);
        }
-       switch (wpa_s->removal_reason) {
+       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;
        }
-       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
-               wpa_s->ifname, gtype, reason);
+       if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
+               wpa_msg_global(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 (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                wpa_s->parent, NULL) > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
+                          "timeout");
+               wpa_s->p2p_in_provisioning = 0;
+       }
 
-       if (ssid)
+       if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
                wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
+#ifdef TIZEN_EXT_P2P
+       /* Currently Tizen uses just one group interface.
+        * So, group index should be decreased when group interface removed.
+       */
+       wpa_s->parent->p2p_group_idx--;
+#endif
        if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
                struct wpa_global *global;
                char *ifname;
@@ -280,12 +367,12 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                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);
+               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;
+               return 1;
        }
 
        wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
@@ -309,11 +396,18 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                 */
                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");
        }
-       wpa_supplicant_ap_deinit(wpa_s);
+       if (wpa_s->ap_iface)
+               wpa_supplicant_ap_deinit(wpa_s);
+       else
+               wpa_drv_deinit_p2p_cli(wpa_s);
+
+       return 0;
 }
 
 
@@ -465,6 +559,76 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
 }
 
 
+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)
 {
@@ -486,13 +650,15 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        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);
+               wpa_msg_global(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);
+       wpa_msg_global(wpa_s->parent, MSG_INFO,
+                      P2P_EVENT_GROUP_FORMATION_SUCCESS);
 
        ssid = wpa_s->current_ssid;
        if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -507,7 +673,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                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->parent->own_addr,
+                       os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr,
                                  ETH_ALEN);
                } else
                        persistent = wpas_p2p_persistent_group(wpa_s,
@@ -532,22 +698,23 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        } 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]" : "");
+               wpa_msg_global(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]" : "");
+               wpa_msg_global(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);
        }
@@ -591,13 +758,16 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
 
        p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
 
-       if (wpa_s->pending_pd_before_join &&
+       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)) {
+            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_printf(MSG_DEBUG, "P2P: Starting pending "
-                          "join-existing-group operation");
-               wpas_p2p_join_start(wpa_s);
+               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;
        }
 }
 
@@ -666,20 +836,37 @@ static void p2p_go_configured(void *ctx, void *data)
                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;
-               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 ? params->passphrase : "",
-                       MAC2STR(wpa_s->parent->own_addr),
-                       params->persistent_group ? " [PERSISTENT]" : "");
+               if (os_strlen(params->passphrase) > 0) {
+                       wpa_msg_global(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_global(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->parent->own_addr);
+                               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);
@@ -700,7 +887,7 @@ static void p2p_go_configured(void *ctx, void *data)
                                          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);
+                                         wpa_s->p2p_pin, NULL, 0, 0);
        os_free(wpa_s->go_params);
        wpa_s->go_params = NULL;
 }
@@ -712,12 +899,18 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ssid *ssid;
 
-       if (wpas_copy_go_neg_results(wpa_s, params) < 0)
+       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)
+       if (ssid == NULL) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
                return;
+       }
 
        wpa_s->show_group_started = 0;
 
@@ -728,6 +921,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        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);
@@ -737,7 +931,22 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        ssid->key_mgmt = WPA_KEY_MGMT_PSK;
        ssid->proto = WPA_PROTO_RSN;
        ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-       ssid->passphrase = os_strdup(params->passphrase);
+       if (os_strlen(params->passphrase) > 0) {
+               ssid->passphrase = os_strdup(params->passphrase);
+               if (ssid->passphrase == NULL) {
+                       wpa_msg_global(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;
@@ -745,6 +954,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        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);
 }
 
@@ -775,6 +986,30 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
        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;
+       d->ignore_old_scan_res = s->ignore_old_scan_res;
+       d->beacon_int = s->beacon_int;
+}
+
+
+static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
+                                     char *ifname, size_t len)
+{
+       char *ifname_ptr = wpa_s->ifname;
+
+       if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
+                      os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+               ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
+       }
+
+       os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, 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);
+       }
 }
 
 
@@ -795,14 +1030,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
                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);
-       }
+       wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
        force_ifname[0] = '\0';
 
        wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -872,7 +1100,13 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
        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;
+       if (wpa_s->conf->ctrl_interface == NULL &&
+           wpa_s->parent != wpa_s &&
+           wpa_s->p2p_mgmt &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
+               iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
+       else
+               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) {
@@ -916,16 +1150,34 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        }
 
        if (res->status) {
-               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
-                       res->status);
+               wpa_msg_global(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;
        }
 
-       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+       if (wpa_s->p2p_go_ht40)
+               res->ht40 = 1;
+
+       wpa_msg_global(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);
@@ -969,8 +1221,8 @@ 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)
 {
        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);
+       wpa_msg_global(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);
 }
@@ -984,13 +1236,38 @@ void wpas_dev_found(void *ctx, const u8 *addr,
        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)),
+#if defined TIZEN_EXT_BUSY_DEVICE // to identify Group Client
+       struct p2p_device *dev;
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       u8 p2p_go_addr[ETH_ALEN];
+
+       os_memset(p2p_go_addr, 0x0, ETH_ALEN);
+
+       dev = p2p_get_device(p2p, addr);
+       if (dev)
+               os_memcpy((void*) p2p_go_addr, (const void*) dev->member_in_go_dev, ETH_ALEN);
+
+       if (!is_zero_ether_addr(p2p_go_addr))
+               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"
+                       "p2p_go_addr=" MACSTR,
+                       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,
+                       MAC2STR(p2p_go_addr));
+       else
+#endif /* TIZEN_EXT_BUSY_DEVICE */
+       wpa_msg_global(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 */
@@ -1003,13 +1280,20 @@ 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));
+       wpa_msg_global(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 void wpas_find_stopped(void *ctx)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+}
+
+
 static int wpas_start_listen(void *ctx, unsigned int freq,
                             unsigned int duration,
                             const struct wpabuf *probe_resp_ie)
@@ -1061,6 +1345,135 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
 }
 
 
+/*
+ * 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)
@@ -1151,13 +1564,40 @@ static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
 }
 
 
+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;
-       struct wpabuf buf;
        u8 *len_pos;
+       int matches = 0;
 
        wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
                          query, query_len);
@@ -1173,39 +1613,52 @@ static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       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);
+       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);
+       }
 
-       wpabuf_set(&buf, query, query_len);
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
-       if (bsrv == NULL) {
+       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);
-               return;
-       }
-
-       /* 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));
-
-       if (wpabuf_tailroom(resp) >=
-           wpabuf_len(bsrv->query) + 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);
 }
 
 
@@ -1326,6 +1779,62 @@ static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
 }
 
 
+#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)
 {
@@ -1352,8 +1861,11 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
                os_free(buf);
        }
 
-       if (wpa_s->p2p_sd_over_ctrl_iface)
+       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)
@@ -1414,6 +1926,12 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
                        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);
@@ -1531,22 +2049,104 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
 }
 
 
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
+#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 wpa_drv_p2p_sd_cancel_request(wpa_s, req);
+               return 0;
        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);
+               return 0;
+       return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
 }
 
 
-void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
-                         const u8 *dst, u8 dialog_token,
-                         const struct wpabuf *resp_tlvs)
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+                               const char *subelems)
 {
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+       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;
@@ -1608,14 +2208,6 @@ int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
 {
        struct p2p_srv_bonjour *bsrv;
 
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
-       if (bsrv) {
-               wpabuf_free(query);
-               wpabuf_free(bsrv->resp);
-               bsrv->resp = resp;
-               return 0;
-       }
-
        bsrv = os_zalloc(sizeof(*bsrv));
        if (bsrv == NULL)
                return -1;
@@ -1683,16 +2275,16 @@ 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);
+       wpa_msg_global(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);
+       wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR
+                      "%s", MAC2STR(peer), params);
 }
 
 
@@ -1744,8 +2336,8 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
        } 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);
+               wpa_msg_global(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,
@@ -1757,19 +2349,7 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 {
        struct wpa_supplicant *wpa_s = ctx;
        unsigned int generated_pin = 0;
-
-       if (config_methods & WPS_CONFIG_DISPLAY)
-               wpas_prov_disc_local_keypad(wpa_s, peer, "");
-       else if (config_methods & WPS_CONFIG_KEYPAD) {
-               generated_pin = wps_generate_pin();
-               wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
-       } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
-               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
-                       MAC2STR(peer));
-
-       wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
-                                           P2P_PROV_DISC_SUCCESS,
-                                           config_methods, generated_pin);
+       char params[20];
 
        if (wpa_s->pending_pd_before_join &&
            (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
@@ -1778,7 +2358,29 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
                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_global(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);
 }
 
 
@@ -1787,15 +2389,45 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
 {
        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_global(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 int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+       if (channels == NULL)
+               return 1; /* Assume no restrictions */
+       return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
 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)
+                                 int *force_freq, int persistent_group,
+                                 const struct p2p_channels *channels)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *s;
@@ -1830,7 +2462,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
                goto accept_inv;
        }
 
-       if (!wpa_s->conf->persistent_reconnect)
+       if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+           os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
+                          "invitation to re-invoke a persistent group");
+       } else if (!wpa_s->conf->persistent_reconnect)
                return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 
        for (s = wpa_s->conf->ssid; s; s = s->next) {
@@ -1870,11 +2506,14 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
        }
 
 accept_inv:
+       wpas_p2p_set_own_freq_preference(wpa_s, 0);
+
        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;
+               wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq);
        }
 
        res = wpa_drv_shared_freq(wpa_s);
@@ -1883,6 +2522,26 @@ accept_inv:
                           "with the channel we are already using on a "
                           "shared interface");
                *force_freq = res;
+               wpas_p2p_set_own_freq_preference(wpa_s, res);
+       }
+
+       if (*force_freq > 0 &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+               if (*go == 0) {
+                       /* We are the client */
+                       wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+                                  "running a GO but we are capable of MCC, "
+                                  "figure out the best channel to use");
+                       *force_freq = 0;
+               } else if (!freq_included(channels, *force_freq)) {
+                       /* We are the GO, and *force_freq is not in the
+                        * intersection */
+                       wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+                                  "in intersection but we are capable of MCC, "
+                                  "figure out the best channel to use",
+                                  *force_freq);
+                       *force_freq = 0;
+               }
        }
 
        return P2P_SC_SUCCESS;
@@ -1909,11 +2568,13 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                           " 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, s->mode == WPAS_MODE_P2P_GO, 0);
+                               wpa_s, s, go, go ? op_freq : 0, 0, NULL);
                } else if (bssid) {
+                       wpa_s->user_initiated_pd = 0;
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-                                     wpa_s->p2p_wps_method);
+                                     wpa_s->p2p_wps_method, 0);
                }
                return;
        }
@@ -1926,44 +2587,130 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 
        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));
+                       wpa_msg_global(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));
+                       wpa_msg_global(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);
+       if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
+               wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+                              "sa=" MACSTR " persistent=%d freq=%d",
+                              MAC2STR(sa), s->id, op_freq);
+       } else {
+               wpa_msg_global(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)
+static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid,
+                                       const u8 *peer)
+{
+       size_t i;
+
+       if (ssid == NULL)
+               return;
+
+       for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
+               if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+                             ETH_ALEN) == 0)
+                       break;
+       }
+       if (i >= ssid->num_p2p_clients) {
+               if (ssid->mode != WPAS_MODE_P2P_GO &&
+                   os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
+                                  "due to invitation result", ssid->id);
+                       wpas_notify_network_removed(wpa_s, ssid);
+                       wpa_config_remove_network(wpa_s->conf, ssid->id);
+                       return;
+               }
+               return; /* Peer not found in client list */
+       }
+
+       wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
+                  "group %d client list due to invitation result",
+                  MAC2STR(peer), ssid->id);
+       os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
+                  ssid->p2p_client_list + (i + 1) * ETH_ALEN,
+                  (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+       ssid->num_p2p_clients--;
+#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_remove_persistent_client(struct wpa_supplicant *wpa_s,
+                                         const u8 *peer)
+{
+       struct wpa_ssid *ssid;
+
+       wpa_s = wpa_s->global->p2p_invite_group;
+       if (wpa_s == NULL)
+               return; /* No known invitation group */
+       ssid = wpa_s->current_ssid;
+       if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+           !ssid->p2p_persistent_group)
+               return; /* Not operating as a GO in persistent group */
+       ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
+                                      ssid->ssid, ssid->ssid_len);
+       wpas_remove_persistent_peer(wpa_s, ssid, peer);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+                                  const struct p2p_channels *channels,
+                                  const u8 *peer)
 {
        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));
+               wpa_msg_global(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);
+               wpa_msg_global(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)
+       wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
+                  status, MAC2STR(peer));
+       if (wpa_s->pending_invite_ssid_id == -1) {
+               if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
+                       wpas_remove_persistent_client(wpa_s, peer);
                return; /* Invitation to active group */
+       }
+
+       if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+               wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
+                          "invitation exchange to indicate readiness for "
+                          "re-invocation");
+       }
 
        if (status != P2P_SC_SUCCESS) {
+               if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
+                       ssid = wpa_config_get_network(
+                               wpa_s->conf, wpa_s->pending_invite_ssid_id);
+                       wpas_remove_persistent_peer(wpa_s, ssid, peer);
+               }
                wpas_p2p_remove_pending_group_interface(wpa_s);
                return;
        }
@@ -1976,8 +2723,47 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
                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, 0);
+                                     ssid->mode == WPAS_MODE_P2P_GO,
+                                     wpa_s->p2p_persistent_go_freq,
+                                     wpa_s->p2p_go_ht40, channels);
+}
+
+
+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++;
 }
 
 
@@ -1991,34 +2777,47 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
 
        /* Operating class 81 - 2.4 GHz band channels 1..13 */
        chan->reg_class[cla].reg_class = 81;
-       chan->reg_class[cla].channels = 11;
-       for (i = 0; i < 11; i++)
-               chan->reg_class[cla].channel[i] = i + 1;
-       cla++;
+       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 = 4;
-       chan->reg_class[cla].channel[0] = 36;
-       chan->reg_class[cla].channel[1] = 40;
-       chan->reg_class[cla].channel[2] = 44;
-       chan->reg_class[cla].channel[3] = 48;
-       cla++;
+       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 = 4;
-       chan->reg_class[cla].channel[0] = 149;
-       chan->reg_class[cla].channel[1] = 153;
-       chan->reg_class[cla].channel[2] = 157;
-       chan->reg_class[cla].channel[3] = 161;
-       cla++;
+       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;
@@ -2040,9 +2839,16 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 }
 
 
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+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) {
@@ -2069,26 +2875,47 @@ struct p2p_oper_class_map {
        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;
-       struct p2p_oper_class_map op_class[] = {
-               { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
-               { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 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 }
-       };
 
        if (wpa_s->hw.modes == NULL) {
                wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
@@ -2108,16 +2935,7 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
                if (mode == NULL)
                        continue;
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-                       int flag;
-                       if (!has_channel(mode, ch, &flag))
-                               continue;
-                       if (o->bw == BW40MINUS &&
-                           (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-                            !has_channel(mode, ch - 4, NULL)))
-                               continue;
-                       if (o->bw == BW40PLUS &&
-                           (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-                            !has_channel(mode, ch + 4, NULL)))
+                       if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
                                continue;
                        if (reg == NULL) {
                                wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2141,6 +2959,32 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 }
 
 
+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)
 {
@@ -2157,6 +3001,73 @@ static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
 }
 
 
+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;
+}
+
+
+static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       wpa_msg_global(wpa_s, level, "P2P: %s", msg);
+}
+
+
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_interface iface;
+       struct wpa_supplicant *p2pdev_wpa_s;
+       char ifname[100];
+       char force_name[100];
+       int ret;
+
+       os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+                   wpa_s->ifname);
+       force_name[0] = '\0';
+       wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+       ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+                            force_name, wpa_s->pending_interface_addr, NULL);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+               return ret;
+       }
+       os_strlcpy(wpa_s->pending_interface_name, ifname,
+                  sizeof(wpa_s->pending_interface_name));
+
+       os_memset(&iface, 0, sizeof(iface));
+       iface.p2p_mgmt = 1;
+       iface.ifname = wpa_s->pending_interface_name;
+       iface.driver = wpa_s->driver->name;
+       iface.driver_param = wpa_s->conf->driver_param;
+       iface.confname = wpa_s->confname;
+       p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+       if (!p2pdev_wpa_s) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+               return -1;
+       }
+       p2pdev_wpa_s->parent = wpa_s;
+
+       wpa_s->pending_interface_name[0] = '\0';
+       return 0;
+}
+
+
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -2195,8 +3106,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        }
 
        os_memset(&p2p, 0, sizeof(p2p));
-       p2p.msg_ctx = wpa_s;
        p2p.cb_ctx = wpa_s;
+       p2p.debug_print = wpas_p2p_debug_print;
        p2p.p2p_scan = wpas_p2p_scan;
        p2p.send_action = wpas_send_action;
        p2p.send_action_done = wpas_send_action_done;
@@ -2204,6 +3115,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        p2p.go_neg_req_rx = wpas_go_neg_req_rx;
        p2p.dev_found = wpas_dev_found;
        p2p.dev_lost = wpas_dev_lost;
+       p2p.find_stopped = wpas_find_stopped;
        p2p.start_listen = wpas_start_listen;
        p2p.stop_listen = wpas_stop_listen;
        p2p.send_probe_resp = wpas_send_probe_resp;
@@ -2216,9 +3128,19 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        p2p.invitation_received = wpas_invitation_received;
        p2p.invitation_result = wpas_invitation_result;
        p2p.get_noa = wpas_get_noa;
-
+       p2p.go_connected = wpas_go_connected;
+
+#if defined(TIZEN_EXT_P2P) && defined(BCM_DRIVER_V115)
+       char buf[64];
+       wpa_s->driver->priv_cmd(wpa_s->drv_priv,  "P2P_DEV_ADDR", buf, sizeof(buf));
+       os_memcpy(wpa_s->global->p2p_dev_addr, buf, ETH_ALEN);
+       wpa_printf(MSG_DEBUG, "P2P: Device address ("MACSTR")", MAC2STR(buf));
+       os_memcpy(p2p.own_addr, wpa_s->own_addr, ETH_ALEN);
+#else
        os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
-       os_memcpy(p2p.dev_addr, wpa_s->own_addr, ETH_ALEN);
+#endif
+
+       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;
@@ -2264,6 +3186,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
                           "%d:%d", p2p.op_reg_class, p2p.op_channel);
        }
+
+       if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
+               p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
+               p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
+       }
+
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
                os_memcpy(p2p.country, wpa_s->conf->country, 2);
                p2p.country[2] = 0x04;
@@ -2299,9 +3227,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 
        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)
@@ -2329,7 +3260,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
                /* Clear any stored provisioning info */
                p2p_clear_provisioning_info(
                        wpa_s->global->p2p,
-                       wpa_s->go_params->peer_interface_addr);
+                       wpa_s->go_params->peer_device_addr);
        }
 
        os_free(wpa_s->go_params);
@@ -2355,19 +3286,18 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
 void wpas_p2p_deinit_global(struct wpa_global *global)
 {
        struct wpa_supplicant *wpa_s, *tmp;
-       char *ifname;
+
+       wpa_s = global->ifaces;
+       if (wpa_s)
+               wpas_p2p_service_flush(wpa_s);
 
        if (global->p2p == NULL)
                return;
 
        /* Remove remaining P2P group interfaces */
-       wpa_s = global->ifaces;
-       if (wpa_s)
-               wpas_p2p_service_flush(wpa_s);
        while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
                wpa_s = wpa_s->next;
        while (wpa_s) {
-               enum wpa_driver_if_type type;
                tmp = global->ifaces;
                while (tmp &&
                       (tmp == wpa_s ||
@@ -2376,12 +3306,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
                }
                if (tmp == NULL)
                        break;
-               ifname = os_strdup(tmp->ifname);
-               type = wpas_p2p_if_type(tmp->p2p_group_interface);
-               wpa_supplicant_remove_iface(global, tmp);
-               if (ifname)
-                       wpa_drv_if_remove(wpa_s, type, ifname);
-               os_free(ifname);
+               /* Disconnect from the P2P group and deinit the interface */
+               wpas_p2p_disconnect(tmp);
        }
 
        /*
@@ -2395,11 +3321,15 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
 
        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->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           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))
@@ -2419,7 +3349,8 @@ 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)
+                                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;
@@ -2430,9 +3361,18 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                                           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);
+                          persistent_group, ssid ? ssid->ssid : NULL,
+                          ssid ? ssid->ssid_len : 0,
+                          wpa_s->p2p_pd_before_go_neg, pref_freq);
 }
 
 
@@ -2440,7 +3380,8 @@ 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)
+                               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;
@@ -2450,7 +3391,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
 
        return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
                             go_intent, own_interface_addr, force_freq,
-                            persistent_group);
+                            persistent_group, ssid ? ssid->ssid : NULL,
+                            ssid ? ssid->ssid_len : 0, pref_freq);
 }
 
 
@@ -2464,9 +3406,84 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
                           " for join operationg - stop join attempt",
                           MAC2STR(wpa_s->pending_join_iface_addr));
                eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-               wpa_msg(wpa_s->parent, MSG_INFO,
-                       P2P_EVENT_GROUP_FORMATION_FAILURE);
+               if (wpa_s->p2p_auto_pd) {
+                       wpa_s->p2p_auto_pd = 0;
+                       wpa_msg_global(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_global(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;
 }
 
 
@@ -2482,12 +3499,78 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        if (wpa_s->global->p2p_disabled)
                return;
 
-       wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
-                  scan_res ? (int) scan_res->num : -1);
+       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_latest(
+                               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_global(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 &&
@@ -2511,7 +3594,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                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);
+       bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
        if (bss) {
                freq = bss->freq;
                wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
@@ -2520,6 +3603,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        if (freq > 0) {
                u16 method;
 
+               if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+                       wpa_msg_global(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)",
@@ -2558,18 +3648,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr, method, 1,
-                                     freq) < 0) {
+                                     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;
                }
-
-               /*
-                * Actual join operation will be started from the Action frame
-                * TX status callback.
-                */
                return;
        }
 
@@ -2585,13 +3670,13 @@ start:
 }
 
 
-static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
 {
-       struct wpa_supplicant *wpa_s = eloop_ctx;
        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));
 
@@ -2601,8 +3686,9 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
        params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE, 0, NULL);
+       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;
@@ -2618,18 +3704,25 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
        wpabuf_put_buf(ies, wps_ie);
        wpabuf_free(wps_ie);
 
-       p2p_scan_ie(wpa_s->global->p2p, ies);
+       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.
         */
-       wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
        ret = wpa_drv_scan(wpa_s, &params);
+       if (!ret) {
+               os_get_time(&wpa_s->scan_trigger_time);
+               wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+       }
 
        wpabuf_free(ies);
 
@@ -2643,13 +3736,24 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+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)
+                        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 ")",
-                  MAC2STR(iface_addr), MAC2STR(dev_addr));
+                  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;
@@ -2667,6 +3771,7 @@ 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)
@@ -2675,14 +3780,38 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
                os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
                          sizeof(group->p2p_pin));
                group->p2p_wps_method = wpa_s->p2p_wps_method;
+       } else {
+               /*
+                * Need to mark the current interface for p2p_group_formation
+                * when a separate group interface is not used. This is needed
+                * to allow p2p_cancel stop a pending p2p_connect-join.
+                * wpas_p2p_init_group_interface() addresses this for the case
+                * where a separate group interface is used.
+                */
+               wpa_s->global->p2p_group_formation = wpa_s;
        }
 
        group->p2p_in_provisioning = 1;
+       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_latest(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);
 
        /*
@@ -2698,36 +3827,105 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+                               int *force_freq, int *pref_freq,
+                               int *oper_freq)
+{
+       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 && *pref_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;
+       }
+
+       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 join, int auth, int go_intent,
-                    int freq)
+                    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, oper_freq = 0;
+       int force_freq = 0, pref_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
-       int ret = 0;
+       int ret = 0, res;
        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;
 
@@ -2735,6 +3933,13 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                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));
@@ -2747,7 +3952,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        } else
                wpa_s->p2p_pin[0] = '\0';
 
-       if (join) {
+       if (join || auto_join) {
                u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
                if (auth) {
                        wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
@@ -2763,59 +3968,34 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
                                         dev_addr);
                }
-               if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
-                   0)
+               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)
+           wpa_s->assoc_freq) {
                oper_freq = wpa_s->assoc_freq;
-       else {
+       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_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;
-       }
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
+       wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
 
        wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -2837,14 +4017,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        if (auth) {
                if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
                                         go_intent, if_addr,
-                                        force_freq, persistent_group) < 0)
+                                        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) < 0) {
+                                 persistent_group, ssid, pref_freq) < 0) {
                if (wpa_s->create_p2p_iface)
                        wpas_p2p_remove_pending_group_interface(wpa_s);
                return -1;
@@ -2853,6 +4034,65 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 }
 
 
+#if defined(TIZEN_EXT_ENROLLEE) && defined(CONFIG_WPS)
+int wpas_p2p_wps_enrollee(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, int wps_method)
+{
+       struct wpa_supplicant *group;
+       struct p2p_device *dev;
+       struct p2p_go_neg_results res;
+       u8 dev_addr[ETH_ALEN];
+       //u8 iface_addr[ETH_ALEN];
+
+       wpa_s->p2p_wps_method = wps_method;
+
+       if (pin)
+               os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
+
+       dev = p2p_get_device(wpa_s->global->p2p, peer_addr);
+       if (dev == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Peer address is not found");
+               return -1;
+       }
+       os_memcpy(wpa_s->pending_join_iface_addr, dev->interface_addr, ETH_ALEN);
+       os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+       wpa_s->pending_join_wps_method = wps_method;
+
+       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;
+
+       wpas_p2p_stop_find(wpa_s);
+
+       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;
+       wpa_printf(MSG_DEBUG, "P2P: WPS Enrollee start for group (iface "
+                  MACSTR " dev " MACSTR ")",
+                  MAC2STR(dev->interface_addr), MAC2STR(dev_addr));
+       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;
+}
+#endif /* TIZEN_EXT_ENROLLEE && CONFIG_WPS */
+
+
 /**
  * wpas_p2p_remain_on_channel_cb - Indication of remain-on-channel start
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -2903,12 +4143,12 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 {
        wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
                   "(p2p_long_listen=%d ms pending_action_tx=%p)",
-                  wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+                  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 (wpa_s->pending_action_tx)
+       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;
@@ -2956,70 +4196,206 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
 }
 
 
-static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
-                                   struct p2p_go_neg_results *params,
-                                   int freq)
+static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+       unsigned int r;
+
+       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;
+       }
+
+       return freq;
+}
+
+
+static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
+                                  struct p2p_go_neg_results *params,
+                                  int freq, int ht40,
+                                  const struct p2p_channels *channels)
 {
        u8 bssid[ETH_ALEN];
        int res;
+       unsigned int pref_freq;
 
        os_memset(params, 0, sizeof(*params));
        params->role_go = 1;
+       params->ht40 = ht40;
        if (freq) {
+               if (!freq_included(channels, freq)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+                                  "accepted", freq);
+                       return -1;
+               }
                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) {
+                  wpa_s->conf->p2p_oper_channel <= 11 &&
+                  freq_included(channels,
+                                2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
                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) {
+       } else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
+                   wpa_s->conf->p2p_oper_reg_class == 116 ||
+                   wpa_s->conf->p2p_oper_reg_class == 117 ||
+                   wpa_s->conf->p2p_oper_reg_class == 124 ||
+                   wpa_s->conf->p2p_oper_reg_class == 126 ||
+                   wpa_s->conf->p2p_oper_reg_class == 127) &&
+                  freq_included(channels,
+                                5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
                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)) {
+                                     wpa_s->best_overall_freq) &&
+                  freq_included(channels, 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)) {
+                                     wpa_s->best_24_freq) &&
+                  freq_included(channels, 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)) {
+                                     wpa_s->best_5_freq) &&
+                  freq_included(channels, 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 if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
+                                                 channels))) {
+               params->freq = pref_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
+                          "channels", params->freq);
        } else {
-               params->freq = 2412;
+               int chan;
+               for (chan = 0; chan < 11; chan++) {
+                       params->freq = 2412 + chan * 5;
+                       if (!wpas_p2p_disallowed_freq(wpa_s->global,
+                                                     params->freq) &&
+                           freq_included(channels, 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;
+               if (!p2p_supported_freq(wpa_s->global->p2p, wpa_s->assoc_freq)
+                   || !freq_included(channels, wpa_s->assoc_freq)) {
+                       if (wpa_s->drv_flags &
+                           WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
+                               wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
+                                          "the channel we are already using "
+                                          "(%u MHz) - allow multi-channel "
+                                          "concurrency", wpa_s->assoc_freq);
+                       } else {
+                               wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
+                                          "the channel we are already using "
+                                          "(%u MHz)", wpa_s->assoc_freq);
+                               return -1;
+                       }
+               } else {
+                       wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we "
+                                  "are already using (%u MHz)",
+                                  wpa_s->assoc_freq);
+                       params->freq = wpa_s->assoc_freq;
+               }
        }
 
        res = wpa_drv_shared_freq(wpa_s);
-       if (res > 0 && !freq) {
+       if (res > 0 && !freq &&
+           (!p2p_supported_freq(wpa_s->global->p2p, res) ||
+            !freq_included(channels, res))) {
+               if (wpa_s->drv_flags &
+                   WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
+                                  "channel we are already using on a shared "
+                                  "interface (%u MHz) - allow multi-channel "
+                                  "concurrency", res);
+               } else {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
+                                  "channel we are already using on a shared "
+                                  "interface (%u MHz)", res);
+                       return -1;
+               }
+       } else 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;
+               if (!freq_included(channels, params->freq)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+                                  "accepted", params->freq);
+                       return -1;
+               }
+       } 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;
 }
 
 
@@ -3029,18 +4405,28 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
 {
        struct wpa_supplicant *group_wpa_s;
 
-       if (!wpas_p2p_create_iface(wpa_s))
+       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_IF_P2P_CLIENT) < 0) {
+               wpa_msg_global(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_global(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;
 }
 
@@ -3056,65 +4442,30 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
  * i.e., without using Group Owner Negotiation.
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-                      int freq)
+                      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(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);
-               }
-       }
+       wpas_p2p_stop_find_oper(wpa_s);
 
-       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);
-               }
-       }
+       freq = wpas_p2p_select_go_freq(wpa_s, freq);
+       if (freq < 0)
+               return -1;
 
-       if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
-               wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+       if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
+               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",
-                          freq);
+                          params.freq);
                return -1;
        }
-
-       wpas_p2p_init_go_params(wpa_s, &params, freq);
        p2p_go_params(wpa_s->global->p2p, &params);
        params.persistent_group = persistent_group;
 
@@ -3173,7 +4524,8 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
 
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                                  struct wpa_ssid *ssid, int addr_allocated,
-                                 int freq)
+                                 int freq, int ht40,
+                                 const struct p2p_channels *channels)
 {
        struct p2p_go_neg_results params;
        int go = 0;
@@ -3189,7 +4541,9 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
        }
 
        /* Make sure we are not running find during connection establishment */
-       wpas_p2p_stop_find(wpa_s);
+       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);
@@ -3197,17 +4551,26 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
        if (ssid->mode != WPAS_MODE_P2P_GO)
                return -1;
 
-       wpas_p2p_init_go_params(wpa_s, &params, freq);
+       freq = wpas_p2p_select_go_freq(wpa_s, freq);
+       if (freq < 0)
+               return -1;
+
+       if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
+               return -1;
 
        params.role_go = 1;
-       if (ssid->passphrase == NULL ||
-           os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
-               wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
-                          "group");
-               return -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_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;
@@ -3261,8 +4624,7 @@ static void wpas_p2p_idle_update(void *ctx, int idle)
 
 
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
-                                      int persistent_group,
-                                      int group_formation)
+                                      struct wpa_ssid *ssid)
 {
        struct p2p_group *group;
        struct p2p_group_config *cfg;
@@ -3276,9 +4638,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        if (cfg == NULL)
                return NULL;
 
-       if (persistent_group && wpa_s->conf->persistent_reconnect)
+       if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
                cfg->persistent_group = 2;
-       else if (persistent_group)
+       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 &&
@@ -3286,6 +4648,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
                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;
@@ -3293,7 +4657,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        group = p2p_group_init(wpa_s->global->p2p, cfg);
        if (group == NULL)
                os_free(cfg);
-       if (!group_formation)
+       if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
                p2p_group_notif_formation_done(group);
        wpa_s->p2p_group = group;
        return group;
@@ -3303,17 +4667,36 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 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;
        }
 
-       /* Clear any stored provisioning info */
-       p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr);
+       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)
@@ -3334,7 +4717,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
        if (wpa_s->go_params) {
                p2p_clear_provisioning_info(
                        wpa_s->global->p2p,
-                       wpa_s->go_params->peer_interface_addr);
+                       wpa_s->go_params->peer_device_addr);
        }
 
        wpas_notify_p2p_wps_failed(wpa_s, fail);
@@ -3342,10 +4725,13 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 
 
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                      const char *config_method, int join)
+                      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)
@@ -3358,16 +4744,35 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                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, join);
+                                                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, join, 0);
+                                config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+                                0, 1);
 }
 
 
@@ -3380,19 +4785,19 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
 
 static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
 {
-       if (!wpa_s->pending_action_tx)
+       if (!offchannel_pending_action_tx(wpa_s))
                return;
 
        wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
                   "operation request");
-       wpabuf_free(wpa_s->pending_action_tx);
-       wpa_s->pending_action_tx = NULL;
+       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)
+                 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;
@@ -3400,30 +4805,42 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
        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)
+       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);
+                       num_req_dev_types, req_dev_types, dev_id,
+                       search_delay);
 }
 
 
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+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->p2p_cb_on_scan_complete = 0;
+       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;
+               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);
 }
 
@@ -3442,6 +4859,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpas_p2p_clear_pending_action_tx(wpa_s);
 
        if (timeout == 0) {
@@ -3489,6 +4907,10 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                return -1;
 
        p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+#ifdef TIZEN_EXT_P2P
+       if (p2p_ie == NULL)
+               return -1;
+#endif
        ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
                               p2p_group, p2p_ie);
        wpabuf_free(p2p_ie);
@@ -3499,15 +4921,27 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 
 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)
+                         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;
 
-       return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
-                               ie, ie_len);
+       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;
+       }
 }
 
 
@@ -3532,7 +4966,7 @@ void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
        if (wpa_s->global->p2p == NULL)
                return;
 
-       p2p_scan_ie(wpa_s->global->p2p, ies);
+       p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
 }
 
 
@@ -3562,13 +4996,40 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 }
 
 
+#ifdef TIZEN_EXT_P2P
+int wpas_p2p_reject_connection(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_connection(wpa_s->global->p2p, addr);
+}
+#endif
+
+
 /* 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)
+                   struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+                   int ht40, int pref_freq)
 {
        enum p2p_invite_role role;
-       u8 *bssid = NULL;
+       u8 *bssid = NULL, bssid_buf[ETH_ALEN];
+       int force_freq = 0, oper_freq = 0;
+       int res;
 
+       wpa_s->global->p2p_invite_group = NULL;
+       if (peer_addr)
+               os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+       else
+               os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+
+       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) {
@@ -3593,6 +5054,22 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        wpa_s->pending_invite_ssid_id = ssid->id;
 
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+           wpa_s->assoc_freq) {
+               oper_freq = wpa_s->assoc_freq;
+               if (bssid == NULL)
+                       bssid = bssid_buf;
+       } else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
+
        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,
@@ -3602,7 +5079,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return -1;
 
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-                         ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
+                         ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+                         1, pref_freq);
 }
 
 
@@ -3612,8 +5090,14 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 {
        struct wpa_global *global = wpa_s->global;
        enum p2p_invite_role role;
-       u8 *bssid = NULL;
+       u8 *bssid = NULL, bssid_buf[ETH_ALEN];
        struct wpa_ssid *ssid;
+       int persistent;
+       int force_freq = 0, oper_freq = 0, pref_freq = 0;
+       int res;
+
+       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)
@@ -3631,11 +5115,16 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
                return -1;
        }
 
+       wpa_s->global->p2p_invite_group = wpa_s;
+       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->parent->own_addr;
+                       go_dev_addr = wpa_s->global->p2p_dev_addr;
        } else {
                role = P2P_INVITE_ROLE_CLIENT;
                if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -3653,14 +5142,31 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
        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, 0);
+                                         go_dev_addr, persistent);
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+           wpa_s->assoc_freq) {
+               oper_freq = wpa_s->assoc_freq;
+               if (bssid == NULL)
+                       bssid = bssid_buf;
+       } else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
+       wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-                         ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
-                         go_dev_addr, 0);
+                         ssid->ssid, ssid->ssid_len, force_freq,
+                         go_dev_addr, persistent, pref_freq);
 }
 
 
@@ -3673,8 +5179,13 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        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)
-               return;
+               goto done;
 
        wpa_s->show_group_started = 0;
 
@@ -3694,20 +5205,20 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        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]" : "");
+               wpa_msg_global(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]" : "");
+               wpa_msg_global(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)
@@ -3716,6 +5227,9 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        if (network_id < 0)
                network_id = ssid->id;
        wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+
+done:
+       wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -3753,8 +5267,15 @@ int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
 
 static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
 {
-       return wpa_s->current_ssid != NULL &&
-               wpa_s->current_ssid->p2p_group &&
+       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;
 }
 
@@ -3771,16 +5292,17 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
 
        wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
                   "group");
-       wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
 }
 
 
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 {
-       unsigned int timeout;
+       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");
 
-       eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
        if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
                return;
 
@@ -3792,6 +5314,37 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
        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,
@@ -3799,27 +5352,48 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 }
 
 
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                          u16 reason_code, const u8 *ie, size_t ie_len)
+/* 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;
+               return 0;
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-               return;
+               return 0;
 
-       p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+       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)
+                            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;
 
-       p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+       if (!locally_generated)
+               p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+                                  ie_len);
 }
 
 
@@ -3935,6 +5509,14 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
                        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");
+               }
+       }
 }
 
 
@@ -3968,9 +5550,10 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
 
                        iface->cross_connect_enabled = 0;
                        iface->cross_connect_in_use = 0;
-                       wpa_msg(iface->parent, MSG_INFO,
-                               P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
-                               iface->ifname, iface->cross_connect_uplink);
+                       wpa_msg_global(iface->parent, MSG_INFO,
+                                      P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                                      iface->ifname,
+                                      iface->cross_connect_uplink);
                }
        }
 
@@ -3997,9 +5580,9 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
                        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);
+               wpa_msg_global(iface->parent, MSG_INFO,
+                              P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                              iface->ifname, iface->cross_connect_uplink);
        }
 }
 
@@ -4017,9 +5600,9 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
                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);
+               wpa_msg_global(iface->parent, MSG_INFO,
+                              P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                              iface->ifname, iface->cross_connect_uplink);
                iface->cross_connect_in_use = 0;
        }
 }
@@ -4033,8 +5616,9 @@ void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
                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);
+       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");
 }
 
 
@@ -4078,9 +5662,9 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
                        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);
+               wpa_msg_global(wpa_s->parent, MSG_INFO,
+                              P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                              wpa_s->ifname, wpa_s->cross_connect_uplink);
                break;
        }
 }
@@ -4126,6 +5710,13 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 }
 
 
+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;
@@ -4146,6 +5737,19 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                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);
@@ -4161,7 +5765,12 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        found = 1;
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                                             wpa_s->parent, NULL);
-                       wpas_p2p_group_delete(wpa_s);
+                       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;
                }
        }
@@ -4182,8 +5791,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
 
        wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
                   "being available anymore");
-       wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
 }
 
 
@@ -4229,31 +5837,194 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
        if (wpa_s == NULL)
                return -1;
 
-       wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
-       wpas_p2p_group_delete(wpa_s);
-
-       return 0;
+       return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ?
+               -1 : 0;
 }
 
 
 int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
 {
+       int ret;
+
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return 0;
 
-       return p2p_in_progress(wpa_s->global->p2p);
+       ret = p2p_in_progress(wpa_s->global->p2p);
+       if (ret == 0) {
+               /*
+                * Check whether there is an ongoing WPS provisioning step (or
+                * other parts of group formation) on another interface since
+                * p2p_in_progress() does not report this to avoid issues for
+                * scans during such provisioning step.
+                */
+               if (wpa_s->global->p2p_group_formation &&
+                   wpa_s->global->p2p_group_formation != wpa_s) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
+                               "in group formation",
+                               wpa_s->global->p2p_group_formation->ifname);
+                       ret = 1;
+               }
+       }
+
+       return ret;
 }
 
 
 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");
-               wpas_p2p_group_formation_timeout(wpa_s->parent, NULL);
+               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;
+}
+
+
+void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
+               "pending anymore (sta_scan_pending=%d "
+               "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
+               wpa_s->global->p2p_cb_on_scan_complete);
+       wpa_s->sta_scan_pending = 0;
+
+       if (!wpa_s->global->p2p_cb_on_scan_complete)
+               return;
+       wpa_s->global->p2p_cb_on_scan_complete = 0;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+
+       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));
        }
 }
index 9a0af1f..24c9de3 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - P2P
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef P2P_SUPPLICANT_H
@@ -19,31 +13,45 @@ enum p2p_wps_method;
 struct p2p_go_neg_results;
 enum p2p_send_action_result;
 struct p2p_peer_info;
+struct p2p_channels;
+struct wps_event_fail;
 
 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_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
 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 join, int auth, int go_intent,
-                    int freq);
+                    int persistent_group, int auto_join, int join,
+                    int auth, int go_intent, int freq, int persistent_id,
+                    int pd, int ht40);
+#if defined(TIZEN_EXT_ENROLLEE) && defined(CONFIG_WPS)
+int wpas_p2p_wps_enrollee(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+                   const char *pin, int wps_method);
+#endif
 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 freq, int ht40);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                                  struct wpa_ssid *ssid, int addr_allocated,
-                                 int freq);
+                                 int freq, int ht40,
+                                 const struct p2p_channels *channels);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
-                                      int persistent_group,
-                                      int group_formation);
+                                      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, int join);
+                      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);
@@ -52,14 +60,16 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
 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);
+                 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);
+                         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);
@@ -84,6 +94,8 @@ 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,
@@ -99,8 +111,12 @@ int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
 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);
+#ifdef TIZEN_EXT_P2P
+int wpas_p2p_reject_connection(struct wpa_supplicant *wpa_s, const u8 *addr);
+#endif
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                   struct wpa_ssid *ssid, const u8 *go_dev_addr);
+                   struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+                   int ht40, int pref_freq);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
                          const u8 *peer_addr, const u8 *go_dev_addr);
 void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -108,10 +124,12 @@ 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);
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                          u16 reason_code, const u8 *ie, size_t ie_len);
+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);
+                            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);
@@ -131,5 +149,22 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 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);
+
+#ifdef CONFIG_P2P
+void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_P2P */
+static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
+{
+}
+#endif /* CONFIG_P2P */
 
 #endif /* P2P_SUPPLICANT_H */
index d38a6bb..ff2ae74 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - test code for pre-authentication
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
@@ -44,12 +38,6 @@ struct preauth_test_data {
 };
 
 
-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);
@@ -244,7 +232,6 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
        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;
@@ -322,7 +309,7 @@ int main(int argc, char *argv[])
        }
 
        os_memset(&wpa_s, 0, sizeof(wpa_s));
-       wpa_s.conf = wpa_config_read(argv[1]);
+       wpa_s.conf = wpa_config_read(argv[1], NULL);
        if (wpa_s.conf == NULL) {
                printf("Failed to parse configuration file '%s'.\n", argv[1]);
                return -1;
index adc6213..bdd6815 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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 "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"
@@ -71,10 +67,13 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_P2P
-       wpa_s->wps->dev.p2p = 1;
-       if (!wps) {
-               wps = 1;
-               *req_type = WPS_REQ_ENROLLEE_INFO;
+       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 */
 
@@ -83,15 +82,33 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_WPS */
 
 
-int wpa_supplicant_enabled_networks(struct wpa_config *conf)
+/**
+ * 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 = conf->ssid;
-       int count = 0;
+       struct wpa_ssid *ssid = wpa_s->conf->ssid;
+       int count = 0, disabled = 0;
        while (ssid) {
-               if (!ssid->disabled)
+               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;
 }
 
@@ -100,7 +117,7 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
                                     struct wpa_ssid *ssid)
 {
        while (ssid) {
-               if (!ssid->disabled)
+               if (!wpas_network_disabled(wpa_s, ssid))
                        break;
                ssid = ssid->next;
        }
@@ -141,7 +158,7 @@ static void int_array_concat(int **res, const int *a)
        reslen = int_array_len(*res);
        alen = int_array_len(a);
 
-       n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
+       n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
        if (n == NULL) {
                os_free(*res);
                *res = NULL;
@@ -192,6 +209,12 @@ static void int_array_sort_unique(int *a)
 }
 
 
+/**
+ * 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)
 {
@@ -204,6 +227,7 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
                wpa_supplicant_notify_scanning(wpa_s, 0);
                wpas_notify_scan_done(wpa_s, 0);
        } else {
+               os_get_time(&wpa_s->scan_trigger_time);
                wpa_s->scan_runs++;
                wpa_s->normal_scans++;
        }
@@ -344,6 +368,16 @@ static void wpa_supplicant_optimize_freqs(
                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 */
 }
 
@@ -373,9 +407,7 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
-static struct wpabuf *
-wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
-                        struct wpa_driver_scan_params *params)
+static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
        struct wpabuf *extra_ie = NULL;
 #ifdef CONFIG_WPS
@@ -394,7 +426,9 @@ wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
 
        if (wps) {
                struct wpabuf *wps_ie;
-               wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+               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) {
@@ -414,34 +448,167 @@ wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
 
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_HS20
+       if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
+               wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
        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;
+}
+
+#endif /* CONFIG_P2P */
+
+/*
+ * 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;
+}
+
+
+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_zalloc((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 wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+                                  struct wpa_driver_scan_params *params)
+{
+       if (wpa_s->hw.modes == NULL)
+               return; /* unknown what channels the driver supports */
+       if (params->freqs)
+               return; /* already using a limited channel set */
+       if (wpa_s->setband == WPA_SETBAND_5G)
+               wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+                                           params);
+       else if (wpa_s->setband == WPA_SETBAND_2G)
+               wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+                                           params);
+}
+
+
 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 *extra_ie;
+       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");
+               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
-       if (wpa_s->disconnected && !wpa_s->scan_req) {
+       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);
+               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
-       if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
-           !wpa_s->scan_req) {
+       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);
+               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
@@ -459,16 +626,19 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 
 #ifdef CONFIG_P2P
-       if (wpas_p2p_in_progress(wpa_s)) {
-               if (wpa_s->wpa_state == WPA_SCANNING) {
+       if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_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);
-               } else {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while "
-                               "P2P operation is in progress");
+                       return;
                }
-               return;
        }
 #endif /* CONFIG_P2P */
 
@@ -481,7 +651,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 
        scan_req = wpa_s->scan_req;
-       wpa_s->scan_req = 0;
+       wpa_s->scan_req = NORMAL_SCAN_REQ;
 
        os_memset(&params, 0, sizeof(params));
 
@@ -490,7 +660,15 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
            wpa_s->wpa_state == WPA_INACTIVE)
                wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 
-       if (scan_req != 2 && wpa_s->connect_without_scan) {
+       /*
+        * 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;
@@ -504,6 +682,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
        }
 
+#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) {
@@ -516,8 +706,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
        }
 
-       if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+       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) {
@@ -532,7 +723,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                if (ssid == NULL && max_ssids > 1)
                        ssid = wpa_s->conf->ssid;
                while (ssid) {
-                       if (!ssid->disabled && ssid->scan_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 =
@@ -552,7 +744,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
 
                for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
-                       if (tssid->disabled)
+                       if (wpas_network_disabled(wpa_s, tssid))
                                continue;
                        if ((params.freqs || !freqs_set) && tssid->scan_freq) {
                                int_array_concat(&params.freqs,
@@ -566,24 +758,44 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                int_array_sort_unique(params.freqs);
        }
 
-       if (ssid) {
-               wpa_s->prev_scan_ssid = ssid;
-               if (max_ssids > 1) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
-                               "the scan request");
-                       params.num_ssids++;
+       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));
                }
-               wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
-                       "SSID(s)");
+       } 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, &params);
+       extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
        if (params.freqs == NULL && wpa_s->next_scan_freqs) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
@@ -592,6 +804,27 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        } else
                os_free(wpa_s->next_scan_freqs);
        wpa_s->next_scan_freqs = NULL;
+       wpa_setband_scan_freqs(wpa_s, &params);
+
+       /* See if user specified frequencies. If so, scan only those. */
+       if (wpa_s->conf->freq_list && !params.freqs) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Optimize scan based on conf->freq_list");
+               int_array_concat(&params.freqs, wpa_s->conf->freq_list);
+       }
+
+       /* Use current associated channel? */
+       if (wpa_s->conf->scan_cur_freq && !params.freqs) {
+               int freq = shared_vif_oper_freq(wpa_s);
+               if (freq > 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current "
+                               "operating channel (%d MHz) since "
+                               "scan_cur_freq is enabled", freq);
+                       params.freqs = os_zalloc(sizeof(int) * 2);
+                       if (params.freqs)
+                               params.freqs[0] = freq;
+               }
+       }
 
        params.filter_ssids = wpa_supplicant_build_filter_ssids(
                wpa_s->conf, &params.num_filter_ssids);
@@ -601,7 +834,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 
 #ifdef CONFIG_P2P
-       if (wpa_s->p2p_in_provisioning) {
+       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.
@@ -610,7 +844,39 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 #endif /* CONFIG_P2P */
 
-       ret = wpa_supplicant_trigger_scan(wpa_s, &params);
+       scan_params = &params;
+
+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);
@@ -620,8 +886,33 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                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;
+       }
+}
+
+
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
+{
+       struct os_time remaining, new_int;
+       int cancelled;
+
+       cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
+                                            &remaining);
+
+       new_int.sec = sec;
+       new_int.usec = 0;
+       if (cancelled && os_time_before(&remaining, &new_int)) {
+               new_int.sec = remaining.sec;
+               new_int.usec = remaining.usec;
        }
+
+       eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
+                              wpa_s, NULL);
+       wpa_s->scan_interval = sec;
 }
 
 
@@ -647,7 +938,8 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
                struct wpa_ssid *ssid = wpa_s->conf->ssid;
 
                while (ssid) {
-                       if (!ssid->disabled && ssid->scan_ssid)
+                       if (!wpas_network_disabled(wpa_s, ssid) &&
+                           ssid->scan_ssid)
                                break;
                        ssid = ssid->next;
                }
@@ -670,6 +962,7 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
  * @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.
@@ -691,6 +984,7 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
 /**
  * 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.
@@ -698,9 +992,10 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
 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;
-       struct wpabuf *wps_ie = NULL;
+       struct wpa_ssid *ssid = NULL;
+       struct wpabuf *extra_ie = NULL;
        int ret;
        unsigned int max_sched_scan_ssids;
        int wildcard = 0;
@@ -713,7 +1008,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                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)
+       if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
                return -1;
 
        if (wpa_s->sched_scanning) {
@@ -723,11 +1018,27 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 
        need_ssids = 0;
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-               if (!ssid->disabled && !ssid->scan_ssid) {
+               if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
                        /* Use wildcard SSID to find this network */
                        wildcard = 1;
-               } else if (!ssid->disabled && ssid->ssid_len)
+               } 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++;
@@ -759,6 +1070,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
            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) {
@@ -773,8 +1089,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 
        if (!ssid || !wpa_s->prev_sched_ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
-
-               wpa_s->sched_scan_interval = 10;
+               if (wpa_s->conf->sched_scan_interval)
+                       wpa_s->sched_scan_interval =
+                               wpa_s->conf->sched_scan_interval;
+               if (wpa_s->sched_scan_interval == 0)
+                       wpa_s->sched_scan_interval = 10;
                wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
                wpa_s->first_sched_scan = 1;
                ssid = wpa_s->conf->ssid;
@@ -787,7 +1106,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        }
 
        while (ssid) {
-               if (ssid->disabled)
+               if (wpas_network_disabled(wpa_s, ssid))
                        goto next;
 
                if (params.num_filter_ssids < wpa_s->max_match_sets &&
@@ -821,6 +1140,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                        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;
                        }
                }
@@ -835,22 +1159,30 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                params.filter_ssids = NULL;
        }
 
-       if (wpa_s->wps)
-               wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
+       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 = &params;
 
+scan:
        if (ssid || !wpa_s->first_sched_scan) {
                wpa_dbg(wpa_s, MSG_DEBUG,
-                       "Starting sched scan: interval %d (no timeout)",
-                       wpa_s->sched_scan_interval);
-       } else {
-               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, &params,
+       wpa_setband_scan_freqs(wpa_s, scan_params);
+
+       ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
                                              wpa_s->sched_scan_interval);
-       wpabuf_free(wps_ie);
+       wpabuf_free(extra_ie);
        os_free(params.filter_ssids);
        if (ret) {
                wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
@@ -868,8 +1200,16 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                wpa_s->first_sched_scan = 0;
                wpa_s->sched_scan_timeout /= 2;
                wpa_s->sched_scan_interval *= 2;
+               if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) {
+                       wpa_s->sched_scan_interval = 10;
+                       wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+               }
        }
 
+       /* If there is no more ssids, start next time from the beginning */
+       if (!ssid)
+               wpa_s->prev_sched_ssid = NULL;
+
        return 0;
 }
 
@@ -885,6 +1225,7 @@ 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);
+       wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -905,6 +1246,16 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *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)
 {
@@ -937,6 +1288,15 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
 }
 
 
+/**
+ * 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;
@@ -956,6 +1316,15 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
 }
 
 
+/**
+ * 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)
 {
@@ -977,6 +1346,16 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
 }
 
 
+/**
+ * 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)
 {
@@ -1008,40 +1387,6 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
 }
 
 
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
-       const struct wpa_scan_res *res, u32 vendor_type)
-{
-       struct wpabuf *buf;
-       const u8 *end, *pos;
-
-       if (res->beacon_ie_len == 0)
-               return NULL;
-       buf = wpabuf_alloc(res->beacon_ie_len);
-       if (buf == NULL)
-               return NULL;
-
-       pos = (const u8 *) (res + 1);
-       pos += res->ie_len;
-       end = pos + res->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;
-}
-
-
 /*
  * 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
@@ -1178,26 +1523,89 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
 
        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",
+                                  "noise=%d level=%d snr=%d%s flags=0x%x "
+                                  "age=%u",
                                   MAC2STR(r->bssid), r->freq, r->qual,
                                   r->noise, r->level, snr,
-                                  snr >= GREAT_SNR ? "*" : "", r->flags);
+                                  snr >= GREAT_SNR ? "*" : "", r->flags,
+                                  r->age);
                } else {
                        wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
-                                  "noise=%d level=%d flags=0x%x",
+                                  "noise=%d level=%d flags=0x%x age=%u",
                                   MAC2STR(r->bssid), r->freq, r->qual,
-                                  r->noise, r->level, r->flags);
+                                  r->noise, r->level, r->flags, r->age);
                }
+               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
@@ -1221,6 +1629,14 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
                return NULL;
        }
+       if (scan_res->fetch_time.sec == 0) {
+               /*
+                * Make sure we have a valid timestamp if the driver wrapper
+                * does not set this.
+                */
+               os_get_time(&scan_res->fetch_time);
+       }
+       filter_scan_res(wpa_s, scan_res);
 
 #ifdef CONFIG_WPS
        if (wpas_wps_in_progress(wpa_s)) {
@@ -1235,26 +1651,27 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
        dump_scan_res(scan_res);
 
        wpa_bss_update_start(wpa_s);
-       for (i = 0; i < scan_res->num; i++) {
-               /*
-                * September, 30th 2011. TIZEN
-                *
-                * TIZEN doesn't want to get scan results
-                * which are under signal level -85dbm.
-                * Therefore, scan results are filtered by signal level under -85dbm
-                */
-#if defined TIZEN_EXT
-               if (scan_res->res[i]->level < -85)
-                       continue;
-#endif
-               wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
-       }
+       for (i = 0; i < scan_res->num; i++)
+               wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
+                                       &scan_res->fetch_time);
        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;
@@ -1265,3 +1682,22 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
 
        return 0;
 }
+
+
+/**
+ * scan_only_handler - Reports scan results
+ */
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
+       wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+       wpas_notify_scan_results(wpa_s);
+       wpas_notify_scan_done(wpa_s, 1);
+}
+
+
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
+{
+       return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
+}
index 7fb84e6..e892479 100644 (file)
@@ -2,20 +2,14 @@
  * WPA Supplicant - Scanning
  * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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_config *conf);
+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);
@@ -36,7 +30,11 @@ 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);
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
-       const struct wpa_scan_res *res, u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+                                     const u8 *bssid);
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res);
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
index c5e47d1..0371628 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -20,6 +14,7 @@
 #include "common/ieee802_11_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "common/wpa_common.h"
+#include "common/sae.h"
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "config.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 */
 
 
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-                     struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+static int index_within_array(const int *array, int idx)
+{
+       int i;
+       for (i = 0; i < idx; i++) {
+               if (array[i] == -1)
+                       return 0;
+       }
+       return 1;
+}
+
+
+static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
+{
+       int *groups = wpa_s->conf->sae_groups;
+       int default_groups[] = { 19, 20, 21, 25, 26 };
+
+       if (!groups)
+               groups = default_groups;
+
+       /* Configuration may have changed, so validate current index */
+       if (!index_within_array(groups, wpa_s->sme.sae_group_index))
+               return -1;
+
+       for (;;) {
+               int group = groups[wpa_s->sme.sae_group_index];
+               if (group < 0)
+                       break;
+               if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+                               wpa_s->sme.sae.group);
+                      return 0;
+               }
+               wpa_s->sme.sae_group_index++;
+       }
+
+       return -1;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
+                                                struct wpa_ssid *ssid,
+                                                const u8 *bssid)
+{
+       struct wpabuf *buf;
+       size_t len;
+
+       if (ssid->passphrase == NULL) {
+               wpa_printf(MSG_DEBUG, "SAE: No password available");
+               return NULL;
+       }
+
+       if (sme_set_sae_group(wpa_s) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
+               return NULL;
+       }
+
+       if (sae_prepare_commit(wpa_s->own_addr, bssid,
+                              (u8 *) ssid->passphrase,
+                              os_strlen(ssid->passphrase),
+                              &wpa_s->sme.sae) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+               return NULL;
+       }
+
+       len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+       buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, 1); /* Transaction seq# */
+       wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+       sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+
+       return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, 2); /* Transaction seq# */
+       wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+       sae_write_confirm(&wpa_s->sme.sae, buf);
+
+       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;
@@ -55,6 +150,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        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 "
@@ -99,6 +197,21 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                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])
@@ -117,7 +230,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
             wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
-               try_opportunistic = ssid->proactive_key_caching &&
+               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,
@@ -131,6 +246,15 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                                "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,
@@ -198,8 +322,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-       wpa_s->sme.mfp = ssid->ieee80211w;
-       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+       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 &&
@@ -227,23 +352,47 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_INTERWORKING
-       if (wpa_s->conf->interworking) {
+#ifdef CONFIG_HS20
+       if (is_hs20_network(wpa_s, ssid, bss)) {
+               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 + 6, pos,
+               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 += 6;
-               *pos++ = WLAN_EID_EXT_CAPAB;
-               *pos++ = 4;
-               *pos++ = 0x00;
-               *pos++ = 0x00;
-               *pos++ = 0x00;
-               *pos++ = 0x80; /* Bit 31 - Interworking */
+               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, ssid,
+                                                        bss->bssid);
+               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 ? SAE_COMMITTED : SAE_CONFIRMED;
        }
-#endif /* CONFIG_INTERWORKING */
+#endif /* CONFIG_SAE */
 
        wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
@@ -265,8 +414,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        if (wpa_drv_authenticate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
                        "driver failed");
-               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                wpas_connection_failed(wpa_s, bss->bssid);
+               wpa_supplicant_mark_disassoc(wpa_s);
+               wpabuf_free(resp);
                return;
        }
 
@@ -277,9 +427,99 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
         * 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)
+{
+#ifdef CONFIG_SAE
+       wpa_s->sme.sae.state = SAE_NOTHING;
+       wpa_s->sme.sae.send_confirm = 0;
+#endif /* CONFIG_SAE */
+       sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+
+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);
+
+       if (auth_transaction == 1 &&
+           status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
+           wpa_s->sme.sae.state == SAE_COMMITTED &&
+           wpa_s->current_bss && wpa_s->current_ssid) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE anti-clogging token "
+                       "requested");
+               wpabuf_free(wpa_s->sme.sae_token);
+               wpa_s->sme.sae_token = wpabuf_alloc_copy(data, len);
+               sme_send_authentication(wpa_s, wpa_s->current_bss,
+                                       wpa_s->current_ssid, 1);
+               return 0;
+       }
+
+       if (auth_transaction == 1 &&
+           status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+           wpa_s->sme.sae.state == SAE_COMMITTED &&
+           wpa_s->current_bss && wpa_s->current_ssid) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+               wpa_s->sme.sae_group_index++;
+               if (sme_set_sae_group(wpa_s) < 0)
+                       return -1; /* no other groups enabled */
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
+               sme_send_authentication(wpa_s, wpa_s->current_bss,
+                                       wpa_s->current_ssid, 1);
+               return 0;
+       }
+
+       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 != SAE_COMMITTED)
+                       return -1;
+               if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
+                                    wpa_s->conf->sae_groups) !=
+                   WLAN_STATUS_SUCCESS)
+                       return -1;
+
+               if (sae_process_commit(&wpa_s->sme.sae) < 0) {
+                       wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
+                                  "commit");
+                       return -1;
+               }
+
+               wpabuf_free(wpa_s->sme.sae_token);
+               wpa_s->sme.sae_token = NULL;
+               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 != SAE_CONFIRMED)
+                       return -1;
+               if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
+                       return -1;
+               wpa_s->sme.sae.state = SAE_ACCEPTED;
+               sae_clear_temp_data(&wpa_s->sme.sae);
+               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;
@@ -304,14 +544,34 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        }
 
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-               " auth_type=%d status_code=%d",
+               " auth_type=%d auth_transaction=%d status_code=%d",
                MAC2STR(data->auth.peer), data->auth.auth_type,
-               data->auth.status_code);
+               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;
+
+               wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
+                          "4-way handshake");
+               wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN);
+       }
+#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);
@@ -321,6 +581,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                    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;
                }
 
@@ -367,17 +628,42 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
 {
        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 */
+#ifdef CONFIG_VHT_OVERRIDES
+       struct ieee80211_vht_capabilities vhtcaps;
+       struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_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);
+       params.pairwise_suite =
+               wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
+       params.group_suite = wpa_cipher_to_suite_driver(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_VHT_OVERRIDES
+       os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+       os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+       params.vhtcaps = &vhtcaps;
+       params.vhtcaps_mask = &vhtcaps_mask;
+       wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_VHT_OVERRIDES */
 #ifdef CONFIG_IEEE80211R
        if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
                params.wpa_ie = wpa_s->sme.ft_ies;
@@ -424,6 +710,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
                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;
        }
@@ -503,8 +790,8 @@ 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");
-       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpa_supplicant_mark_disassoc(wpa_s);
 }
 
 
@@ -596,9 +883,259 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_IEEE80211W
        sme_stop_sa_query(wpa_s);
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       wpabuf_free(wpa_s->sme.sae_token);
+       wpa_s->sme.sae_token = NULL;
+       sae_clear_data(&wpa_s->sme.sae);
+#endif /* CONFIG_SAE */
 
        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);
+}
+
+
+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 */
+               enum hostapd_hw_mode mode;
+               mode = ieee80211_freq_to_chan(bss->freq, &channel);
+               if (mode != HOSTAPD_MODE_IEEE80211G &&
+                   mode != HOSTAPD_MODE_IEEE80211B)
+                       continue;
+
+               ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+               ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+               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);
 }
 
 
@@ -655,9 +1192,9 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
            sme_check_sa_query_timeout(wpa_s))
                return;
 
-       nbuf = os_realloc(wpa_s->sme.sa_query_trans_id,
-                         (wpa_s->sme.sa_query_count + 1) *
-                         WLAN_SA_QUERY_TR_ID_LEN);
+       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) {
@@ -702,12 +1239,12 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
 {
        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 == 0)
+       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;
index a59b38d..a7cc507 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - SME
  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SME_H
@@ -41,6 +35,9 @@ 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,
@@ -101,6 +98,16 @@ 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 */
diff --git a/wpa_supplicant/symbian/README.symbian b/wpa_supplicant/symbian/README.symbian
deleted file mode 100644 (file)
index 9d3b811..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-wpa_supplicant for Symbian
-==========================
-
-Copyright (c) 2003-2007, Jouni Malinen <j@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 directory includes project files for testing experimental Symbian
-(e.g., Nokia S60 3rd Ed) builds. The Symbian port is not really
-complete or expected to work, but these files can be used to verify
-that the build itself can be completed successfully.
-
-These files have been successfully tested with Nokia S60 3rd Edition
-MR SDK.
-
-Build files can be created and a phone release build can be run with
-following commands:
-
-bldmake bldfiles
-abld build gcce urel
diff --git a/wpa_supplicant/symbian/bld.inf b/wpa_supplicant/symbian/bld.inf
deleted file mode 100644 (file)
index a1fc582..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-PRJ_PLATFORMS
-WINSCW GCCE
-
-PRJ_EXPORTS
-
-PRJ_MMPFILES
-
-wpa_supplicant.mmp
diff --git a/wpa_supplicant/symbian/wpa_supplicant.mmp b/wpa_supplicant/symbian/wpa_supplicant.mmp
deleted file mode 100644 (file)
index e018e05..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-TARGET         wpa_supplicant.exe
-UID            0x0 0x0
-VENDORID       0
-TARGETTYPE     exe
-
-SYSTEMINCLUDE \epoc32\include \epoc32\include\variant \epoc32\include\ecom \epoc32\include\libc
-
-USERINCLUDE    .. ..\..\src ..\..\src\utils
-
-SOURCEPATH     ..
-SOURCE         main_symbian.cpp
-SOURCE         config.c config_file.c
-SOURCE         eapol_sm.c
-SOURCE         wpa_supplicant.c events.c
-SOURCEPATH     ..\..\src\rsn_supp
-SOURCE         wpa.c preauth.c pmksa_cache.c peerkey.c wpa_ie.c
-SOURCEPATH     ..\..\src\drivers
-SOURCE         drivers.c driver_common.c
-SOURCEPATH     ..\..\src\common
-SOURCE         wpa_common.c
-SOURCEPATH     ..\..\src\utils
-SOURCE         os_none.c common.c wpa_debug.c eloop_none.c base64.c
-SOURCEPATH     ..\..\src\crypto
-SOURCE         sha1.c md5.c rc4.c des.c aes-cbc.c aes-ctr.c aes-eax.c aes-encblock.c aes-omac1.c aes-unwrap.c aes-wrap.c aes.c ms_funcs.c
-SOURCE         tls_internal.c crypto_internal.c
-SOURCEPATH     ..\..\src\tls
-SOURCE         asn1.c bignum.c rsa.c x509v3.c tlsv1_client.c tlsv1_common.c
-SOURCEPATH     ..\..\src\l2_packet
-SOURCE         l2_packet_none.c
-SOURCEPATH     ..\..\src\eap_peer
-SOURCE         eap.c eap_methods.c
-SOURCE         eap_md5.c eap_tls.c eap_mschapv2.c eap_peap.c eap_gtc.c
-SOURCE         eap_ttls.c eap_otp.c eap_leap.c eap_tls_common.c eap_tlv.c
-SOURCE         eap_fast.c eap_fast_pac.c
-SOURCEPATH     ..\..\src\eap_common
-SOURCE         eap_common.c
-
-LIBRARY                euser.lib estlib.lib
@@ -10,4 +10,4 @@ Type=simple
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
 
 [Install]
-Alias=network.target.wants/wpa_supplicant-nl80211@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
@@ -10,4 +10,4 @@ Type=simple
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
 
 [Install]
-Alias=network.target.wants/wpa_supplicant-wired@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
@@ -10,4 +10,4 @@ Type=simple
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
 
 [Install]
-Alias=network.target.wants/wpa_supplicant@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant@%i.service
index 5b947ac..4351ad8 100644 (file)
@@ -7,5 +7,5 @@ BusName=fi.epitest.hostap.WPASupplicant
 ExecStart=@BINDIR@/wpa_supplicant -u
 
 [Install]
-WantedBy=network.target
+WantedBy=multi-user.target
 Alias=dbus-fi.epitest.hostap.WPASupplicant.service
index deb19f6..f60b182 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for EAP-SIM PRF
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "eap_common/eap_sim_common.c"
@@ -34,7 +28,7 @@ static int test_eap_sim_prf(void)
 
        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)) {
+       if (memcmp(w, buf, sizeof(w)) != 0) {
                printf("eap_sim_prf failed\n");
                return 1;
        }
index 7947137..ba2be6f 100644 (file)
@@ -2,14 +2,8 @@
  * Test program for combined WPA authenticator/supplicant
  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -20,7 +14,7 @@
 #include "../config.h"
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/wpa_ie.h"
-#include "../hostapd/wpa.h"
+#include "ap/wpa_auth.h"
 
 
 extern int wpa_debug_level;
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
new file mode 100755 (executable)
index 0000000..65e2fa1
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012, Intel Corporation
+#
+# Author: Johannes Berg <johannes@sipsolutions.net>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import sys, struct, re
+
+def write_pcap_header(pcap_file):
+    pcap_file.write(
+        struct.pack('<IHHIIII',
+                    0xa1b2c3d4, 2, 4, 0, 0, 65535,
+                    105 # raw 802.11 format
+                    ))
+
+def pcap_addpacket(pcap_file, ts, data):
+    # ts in seconds, float
+    pcap_file.write(struct.pack('<IIII',
+        int(ts), int(1000000 * ts) % 1000000,
+        len(data), len(data)))
+    pcap_file.write(data)
+
+if __name__ == "__main__":
+    try:
+        input = sys.argv[1]
+        pcap = sys.argv[2]
+    except IndexError:
+        print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+        sys.exit(2)
+
+    input_file = open(input, 'r')
+    pcap_file = open(pcap, 'w')
+    frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)')
+
+    write_pcap_header(pcap_file)
+
+    for line in input_file:
+        m = frame_re.match(line)
+        if m is None:
+            continue
+        if m.group(2):
+            ts = float(m.group(2))
+        else:
+            ts = 0
+        hexdata = m.group(3)
+        hexdata = hexdata.split()
+        data = ''.join([chr(int(x, 16)) for x in hexdata])
+        pcap_addpacket(pcap_file, ts, data)
+
+    input_file.close()
+    pcap_file.close()
index 38b29c4..af7b3fe 100755 (executable)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-prf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"\r
                                >\r
                        </File>\r
index b107842..97aa2c5 100755 (executable)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-prf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"\r
                                >\r
                        </File>\r
index e3886b7..51acab9 100755 (executable)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-prf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"\r
                                >\r
                        </File>\r
index 1034891..6fd8af8 100755 (executable)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\..\src\crypto\sha1-prf.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"\r
                                >\r
                        </File>\r
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
new file mode 100644 (file)
index 0000000..92ca536
--- /dev/null
@@ -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);
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
new file mode 100644 (file)
index 0000000..b75d4f2
--- /dev/null
@@ -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 */
index 0e1532e..39634d9 100644 (file)
@@ -2,14 +2,8 @@
  * win_if_list - Display network interfaces with description (for Windows)
  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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.
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
new file mode 100644 (file)
index 0000000..4f8d895
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "ctrl_iface.h"
+#include "bss.h"
+#include "wnm_sta.h"
+
+#define MAX_TFS_IE_LEN  1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
+
+
+/* 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);
+       }
+}
+
+
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+       int i;
+
+       for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+               os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].bearing);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap);
+               os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+       }
+
+       os_free(wpa_s->wnm_neighbor_report_elements);
+       wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+                                          u8 id, u8 elen, const u8 *pos)
+{
+       switch (id) {
+       case WNM_NEIGHBOR_TSF:
+               if (elen < 2 + 2) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+                       break;
+               }
+               rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
+               if (rep->tsf_info == NULL)
+                       break;
+               rep->tsf_info->present = 1;
+               os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
+               os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+               break;
+       case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+               if (elen < 2) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+                                  "country string");
+                       break;
+               }
+               rep->con_coun_str =
+                       os_zalloc(sizeof(struct condensed_country_string));
+               if (rep->con_coun_str == NULL)
+                       break;
+               rep->con_coun_str->present = 1;
+               os_memcpy(rep->con_coun_str->country_string, pos, 2);
+               break;
+       case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+               if (elen < 1) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+                                  "candidate");
+                       break;
+               }
+               rep->bss_tran_can =
+                       os_zalloc(sizeof(struct bss_transition_candidate));
+               if (rep->bss_tran_can == NULL)
+                       break;
+               rep->bss_tran_can->present = 1;
+               rep->bss_tran_can->preference = pos[0];
+               break;
+       case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+               if (elen < 12) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
+                                  "duration");
+                       break;
+               }
+               rep->bss_term_dur =
+                       os_zalloc(sizeof(struct bss_termination_duration));
+               if (rep->bss_term_dur == NULL)
+                       break;
+               rep->bss_term_dur->present = 1;
+               os_memcpy(rep->bss_term_dur->duration, pos, 12);
+               break;
+       case WNM_NEIGHBOR_BEARING:
+               if (elen < 8) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+                                  "bearing");
+                       break;
+               }
+               rep->bearing = os_zalloc(sizeof(struct bearing));
+               if (rep->bearing == NULL)
+                       break;
+               rep->bearing->present = 1;
+               os_memcpy(rep->bearing->bearing, pos, 8);
+               break;
+       case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+               if (elen < 2) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+                                  "pilot");
+                       break;
+               }
+               rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+               if (rep->meas_pilot == NULL)
+                       break;
+               rep->meas_pilot->present = 1;
+               rep->meas_pilot->measurement_pilot = pos[0];
+               rep->meas_pilot->num_vendor_specific = pos[1];
+               os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2);
+               break;
+       case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+               if (elen < 4) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+                                  "capabilities");
+                       break;
+               }
+               rep->rrm_cap =
+                       os_zalloc(sizeof(struct rrm_enabled_capabilities));
+               if (rep->rrm_cap == NULL)
+                       break;
+               rep->rrm_cap->present = 1;
+               os_memcpy(rep->rrm_cap->capabilities, pos, 4);
+               break;
+       case WNM_NEIGHBOR_MULTIPLE_BSSID:
+               if (elen < 2) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+                       break;
+               }
+               rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+               if (rep->mul_bssid == NULL)
+                       break;
+               rep->mul_bssid->present = 1;
+               rep->mul_bssid->max_bssid_indicator = pos[0];
+               rep->mul_bssid->num_vendor_specific = pos[1];
+               os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2);
+               break;
+       }
+}
+
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+                                     const u8 *pos, u8 len,
+                                     struct neighbor_report *rep)
+{
+       u8 left = len;
+
+       if (left < 13) {
+               wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+               return;
+       }
+
+       os_memcpy(rep->bssid, pos, ETH_ALEN);
+       os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+       rep->regulatory_class = *(pos + 10);
+       rep->channel_number = *(pos + 11);
+       rep->phy_type = *(pos + 12);
+
+       pos += 13;
+       left -= 13;
+
+       while (left >= 2) {
+               u8 id, elen;
+
+               id = *pos++;
+               elen = *pos++;
+               wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+               left -= 2 + elen;
+               pos += elen;
+       }
+}
+
+
+static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
+                                        struct wpa_scan_results *scan_res,
+                                        struct neighbor_report *neigh_rep,
+                                        u8 num_neigh_rep, u8 *bssid_to_connect)
+{
+
+       u8 i, j;
+
+       if (scan_res == NULL || num_neigh_rep == 0)
+               return 0;
+
+       for (i = 0; i < num_neigh_rep; i++) {
+               for (j = 0; j < scan_res->num; j++) {
+                       /* Check for a better RSSI AP */
+                       if (os_memcmp(scan_res->res[j]->bssid,
+                                     neigh_rep[i].bssid, ETH_ALEN) == 0 &&
+                           scan_res->res[j]->level >
+                           wpa_s->current_bss->level) {
+                               /* Got a BSSID with better RSSI value */
+                               os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
+                                         ETH_ALEN);
+                               return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+static void wnm_send_bss_transition_mgmt_resp(
+       struct wpa_supplicant *wpa_s, u8 dialog_token,
+       enum bss_trans_mgmt_status_code status, u8 delay,
+       const u8 *target_bssid)
+{
+       u8 buf[1000], *pos;
+       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);
+}
+
+
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res)
+{
+       u8 bssid[ETH_ALEN];
+
+       if (scan_res == NULL) {
+               wpa_printf(MSG_ERROR, "Scan result is NULL");
+               goto send_bss_resp_fail;
+       }
+
+       /* Compare the Neighbor Report and scan results */
+       if (compare_scan_neighbor_results(wpa_s, scan_res,
+                                         wpa_s->wnm_neighbor_report_elements,
+                                         wpa_s->wnm_num_neighbor_report,
+                                         bssid) == 1) {
+               /* Associate to the network */
+               struct wpa_bss *bss;
+               struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+               bss = wpa_bss_get_bssid(wpa_s, bssid);
+               if (!bss) {
+                       wpa_printf(MSG_DEBUG, "WNM: Target AP not found from "
+                                  "BSS table");
+                       goto send_bss_resp_fail;
+               }
+
+               /* Send the BSS Management Response - Accept */
+               if (wpa_s->wnm_reply) {
+                       wnm_send_bss_transition_mgmt_resp(wpa_s,
+                                                 wpa_s->wnm_dialog_token,
+                                                 WNM_BSS_TM_ACCEPT,
+                                                 0, NULL);
+               }
+
+               wpa_s->reassociate = 1;
+               wpa_supplicant_connect(wpa_s, bss, ssid);
+               wnm_deallocate_memory(wpa_s);
+               return;
+       }
+
+       /* Send reject response for all the failures */
+send_bss_resp_fail:
+       wnm_deallocate_memory(wpa_s);
+       if (wpa_s->wnm_reply) {
+               wnm_send_bss_transition_mgmt_resp(wpa_s,
+                                                 wpa_s->wnm_dialog_token,
+                                                 WNM_BSS_TM_REJECT_UNSPECIFIED,
+                                                 0, NULL);
+       }
+       return;
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+                                            const u8 *pos, const u8 *end,
+                                            int reply)
+{
+       if (pos + 5 > end)
+               return;
+
+       wpa_s->wnm_dialog_token = pos[0];
+       wpa_s->wnm_mode = pos[1];
+       wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+       wpa_s->wnm_validity_interval = pos[4];
+       wpa_s->wnm_reply = reply;
+
+       wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+                  "dialog_token=%u request_mode=0x%x "
+                  "disassoc_timer=%u validity_interval=%u",
+                  wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+                  wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+
+       pos += 5;
+
+       if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+               if (pos + 12 > end) {
+                       wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+                       return;
+               }
+               os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
+               pos += 12; /* BSS Termination Duration */
+       }
+
+       if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
+               char url[256];
+               unsigned int beacon_int;
+
+               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';
+               pos += 1 + pos[0];
+
+               if (wpa_s->current_bss)
+                       beacon_int = wpa_s->current_bss->beacon_int;
+               else
+                       beacon_int = 100; /* best guess */
+
+               wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+                       wpa_sm_pmf_enabled(wpa_s->wpa),
+                       wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
+       }
+
+       if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+               wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
+                       "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+               if (wpa_s->wnm_dissoc_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 (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+               wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+               wpa_s->wnm_num_neighbor_report = 0;
+               os_free(wpa_s->wnm_neighbor_report_elements);
+               wpa_s->wnm_neighbor_report_elements = os_zalloc(
+                       WNM_MAX_NEIGHBOR_REPORT *
+                       sizeof(struct neighbor_report));
+               if (wpa_s->wnm_neighbor_report_elements == NULL)
+                       return;
+
+               while (pos + 2 <= end &&
+                      wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+               {
+                       u8 tag = *pos++;
+                       u8 len = *pos++;
+
+                       wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+                                  tag);
+                       if (pos + len > end) {
+                               wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+                               return;
+                       }
+                       wnm_parse_neighbor_report(
+                               wpa_s, pos, len,
+                               &wpa_s->wnm_neighbor_report_elements[
+                                       wpa_s->wnm_num_neighbor_report]);
+
+                       pos += len;
+                       wpa_s->wnm_num_neighbor_report++;
+               }
+
+               wpa_s->scan_res_handler = wnm_scan_response;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       } else if (reply) {
+               enum bss_trans_mgmt_status_code status;
+               if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+                       status = WNM_BSS_TM_ACCEPT;
+               else {
+                       wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
+                       status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+               }
+               wnm_send_bss_transition_mgmt_resp(wpa_s,
+                                                 wpa_s->wnm_dialog_token,
+                                                 status, 0, NULL);
+       }
+}
+
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+                                      u8 query_reason)
+{
+       u8 buf[1000], *pos;
+       struct ieee80211_mgmt *mgmt;
+       size_t len;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+                  MACSTR " query_reason=%u",
+                  MAC2STR(wpa_s->bssid), query_reason);
+
+       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_query.action = WNM_BSS_TRANS_MGMT_QUERY;
+       mgmt->u.action.u.bss_tm_query.dialog_token = 0;
+       mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
+       pos = mgmt->u.action.u.bss_tm_query.variable;
+
+       len = pos - (u8 *) &mgmt->u.action.category;
+
+       ret = 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);
+
+       return ret;
+}
+
+
+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:
+               wpa_printf(MSG_ERROR, "WNM: Unknown request");
+               break;
+       }
+}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
new file mode 100644 (file)
index 0000000..2933926
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+struct tsf_info {
+       u8 present;
+       u8 tsf_offset[2];
+       u8 beacon_interval[2];
+};
+
+struct condensed_country_string {
+       u8 present;
+       u8 country_string[2];
+};
+
+struct bss_transition_candidate {
+       u8 present;
+       u8 preference;
+};
+
+struct bss_termination_duration {
+       u8 present;
+       u8 duration[12];
+};
+
+struct bearing {
+       u8 present;
+       u8 bearing[8];
+};
+
+struct measurement_pilot {
+       u8 present;
+       u8 measurement_pilot;
+       u8 num_vendor_specific;
+       u8 vendor_specific[255];
+};
+
+struct rrm_enabled_capabilities {
+       u8 present;
+       u8 capabilities[4];
+};
+
+struct multiple_bssid {
+       u8 present;
+       u8 max_bssid_indicator;
+       u8 num_vendor_specific;
+       u8 vendor_specific[255];
+};
+
+struct neighbor_report {
+       u8 bssid[ETH_ALEN];
+       u8 bssid_information[4];
+       u8 regulatory_class;
+       u8 channel_number;
+       u8 phy_type;
+       struct tsf_info *tsf_info;
+       struct condensed_country_string *con_coun_str;
+       struct bss_transition_candidate *bss_tran_can;
+       struct bss_termination_duration *bss_term_dur;
+       struct bearing *bearing;
+       struct measurement_pilot *meas_pilot;
+       struct rrm_enabled_capabilities *rrm_cap;
+       struct multiple_bssid *mul_bssid;
+};
+
+
+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);
+
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+                      struct wpa_scan_results *scan_res);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+                                      u8 query_reason);
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
+#endif /* WNM_STA_H */
index 6ca7939..a77e767 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -26,6 +20,7 @@
 #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-2011, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2013, Jouni Malinen <j@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";
+"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 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"
+"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"
@@ -103,6 +81,7 @@ static const char *pid_file = NULL;
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
+static char *ifname_prefix = NULL;
 
 struct cli_txt_entry {
        struct dl_list list;
@@ -112,10 +91,14 @@ struct cli_txt_entry {
 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 DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
 
 
-static void print_help(void);
+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)
@@ -132,7 +115,7 @@ static void usage(void)
               "  -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();
+       print_help(NULL);
 }
 
 
@@ -184,7 +167,6 @@ static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
 }
 
 
-#ifdef CONFIG_P2P
 static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
 {
        const char *end;
@@ -192,15 +174,12 @@ static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
        end = os_strchr(txt, ' ');
        if (end == NULL)
                end = txt + os_strlen(txt);
-       buf = os_malloc(end - txt + 1);
+       buf = dup_binstr(txt, end - txt);
        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)
@@ -222,7 +201,6 @@ static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
 }
 
 
-#ifdef CONFIG_P2P
 static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
 {
        u8 addr[ETH_ALEN];
@@ -242,16 +220,13 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
        end = os_strchr(txt, ' ');
        if (end == NULL)
                end = txt + os_strlen(txt);
-       buf = os_malloc(end - txt + 1);
+       buf = dup_binstr(txt, end - txt);
        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)
@@ -260,7 +235,7 @@ static char ** cli_txt_list_array(struct dl_list *txt_list)
        char **res;
        struct cli_txt_entry *e;
 
-       res = os_zalloc((count + 1) * sizeof(char *));
+       res = os_calloc(count + 1, sizeof(char *));
        if (res == NULL)
                return NULL;
 
@@ -383,6 +358,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
                } else {
                        printf("Warning: Failed to attach to "
                               "wpa_supplicant.\n");
+                       wpa_cli_close_connection();
                        return -1;
                }
        }
@@ -418,7 +394,7 @@ static void wpa_cli_msg_cb(char *msg, size_t len)
 
 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
 {
-       char buf[2048];
+       char buf[4096];
        size_t len;
        int ret;
 
@@ -426,6 +402,12 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
                printf("Not connected to wpa_supplicant - command dropped.\n");
                return -1;
        }
+       if (ifname_prefix) {
+               os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+                           ifname_prefix, cmd);
+               buf[sizeof(buf) - 1] = '\0';
+               cmd = buf;
+       }
        len = sizeof(buf) - 1;
        ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
                               wpa_cli_msg_cb);
@@ -452,6 +434,58 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
 }
 
 
+static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+                    char *argv[])
+{
+       int i, res;
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + buflen;
+
+       res = os_snprintf(pos, end - pos, "%s", cmd);
+       if (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[4096];
+       if (argc < min_args) {
+               printf("Invalid %s command - at least %d argument%s "
+                      "required.\n", cmd, min_args,
+                      min_args > 1 ? "s are" : " is");
+               return -1;
+       }
+       if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int 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)
@@ -476,14 +510,7 @@ static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256];
-       int ret;
-       if (argc == 0)
-               return -1;
-       ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
-       if (ret < 0 || (size_t) ret >= sizeof(cmd))
-               return -1;
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
 }
 
 
@@ -501,11 +528,26 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       print_help();
+       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);
@@ -522,72 +564,87 @@ static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
-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) {
+               res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+               if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+                       printf("Too long SET command.\n");
+                       return -1;
+               }
+               return wpa_ctrl_command(ctrl, cmd);
        }
 
-       if (argc != 1 && argc != 2) {
-               printf("Invalid SET command: needs two arguments (variable "
-                      "name and value)\n");
-               return -1;
-       }
+       return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
+}
 
-       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;
+
+static char ** wpa_cli_complete_set(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       const char *fields[] = {
+               /* runtime values */
+               "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
+               "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
+               "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
+               "wps_fragment_size", "wps_version_number", "ampdu",
+               "tdls_testing", "tdls_disabled", "pno", "radio_disabled",
+               "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
+               "no_keep_alive",
+               /* global configuration parameters */
+               "eapol_version", "ap_scan", "disable_scan_offload",
+               "fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
+               "pkcs11_module_path", "pcsc_reader", "pcsc_pin",
+               "driver_param", "dot11RSNAConfigPMKLifetime",
+               "dot11RSNAConfigPMKReauthThreshold",
+               "dot11RSNAConfigSATimeout",
+               "update_config", "load_dynamic_eap", "uuid", "device_name",
+               "manufacturer", "model_name", "model_number", "serial_number",
+               "device_type", "os_version", "config_methods",
+               "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+               "p2p_listen_reg_class", "p2p_listen_channel",
+               "p2p_oper_reg_class", "p2p_oper_channel",
+               "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
+               "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+               "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+               "p2p_ignore_shared_freq", "country", "bss_max_count",
+               "bss_expiration_age", "bss_expiration_scan_count",
+               "filter_ssids", "filter_rssi", "max_num_sta",
+               "disassoc_low_ack", "hs20", "interworking", "hessid",
+               "access_network_type", "pbc_in_m1", "autoscan",
+               "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
+               "wps_nfc_dev_pw", "ext_password_backend",
+               "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+               "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
+               "ignore_old_scan_res", "freq_list"
+       };
+       int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+
+       if (arg == 1) {
+               char **res = os_calloc(num_fields + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; i < num_fields; i++) {
+                       res[i] = os_strdup(fields[i]);
+                       if (res[i] == NULL)
+                               return res;
+               }
+               return res;
        }
-       return wpa_ctrl_command(ctrl, cmd);
+
+       if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
+               return cli_txt_list_array(&bsses);
+
+       return NULL;
 }
 
 
 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid GET command: need 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);
+       return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
 }
 
 
@@ -613,97 +670,48 @@ static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
 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);
+       return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
 }
 
 
 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);
+       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[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid SCAN_INTERVAL command: needs one argument "
-                      "scan_interval value)\n");
-               return -1;
-       }
-       res = os_snprintf(cmd, sizeof(cmd), "SCAN_INTERVAL %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long SCAN_INTERVAL command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid BSS_EXPIRE_AGE command: needs one argument "
-                      "(bss_expire_age value)\n");
-               return -1;
-       }
-       res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long BSS_EXPIRE_AGE command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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) {
-               printf("Invalid BSS_EXPIRE_COUNT command: needs one argument "
-                      "(bss_expire_count value)\n");
-               return -1;
-       }
-       res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]);
+       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_EXPIRE_COUNT command.\n");
+               printf("Too long BSS_FLUSH command.\n");
                return -1;
        }
        return wpa_ctrl_command(ctrl, cmd);
@@ -713,69 +721,24 @@ static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
 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);
+       return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
 }
 
 
 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);
+       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[])
 {
-       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);
+       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[])
 {
-       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"
@@ -784,49 +747,14 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
                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);
+       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[])
 {
-       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);
+       return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
 }
 
 
@@ -837,60 +765,150 @@ static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256];
-       int res;
+       return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
+}
 
-       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");
+
+static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, 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;
        }
 
-       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");
+       buflen = 18 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
                return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
 }
-#endif /* CONFIG_WPS_OOB */
 
 
-static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_nfc_get_handover_req(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;
+       return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
 
-               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';
+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;
+}
+
+
+static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
+}
+
+#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')
@@ -930,41 +948,14 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
 static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
                                  char *argv[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc < 1) {
-               printf("Invalid WPS_AP_PIN command: needs at least one "
-                      "argument\n");
-               return -1;
-       }
-
-       if (argc > 2)
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else if (argc > 1)
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s",
-                                 argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long WPS_AP_PIN command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[100];
-       if (argc > 0) {
-               os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
-               return wpa_ctrl_command(ctrl, cmd);
-       }
-       return wpa_ctrl_command(ctrl, "WPS_ER_START");
+       return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
 }
 
 
@@ -979,9 +970,6 @@ static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
 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 at least two "
                       "arguments:\n"
@@ -991,48 +979,20 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       if (argc > 2)
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else
-               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);
+       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[])
 {
-       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);
+       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[])
 {
-       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"
@@ -1040,22 +1000,13 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
                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);
+       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[])
 {
-       char cmd[256];
-       int res;
-
        if (argc != 2) {
                printf("Invalid WPS_ER_SET_CONFIG command: need two "
                       "arguments:\n"
@@ -1064,13 +1015,7 @@ static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_SET_CONFIG %s %s",
-                         argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long WPS_ER_SET_CONFIG command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
 }
 
 
@@ -1125,42 +1070,32 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
+#ifdef CONFIG_WPS_NFC
+static int wpa_cli_cmd_wps_er_nfc_config_token(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");
+       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;
        }
 
-       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);
+       return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
 }
+#endif /* CONFIG_WPS_NFC */
 
 
-static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256];
-       int res;
+       return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
+}
 
-       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_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
 }
 
 
@@ -1365,85 +1300,25 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
 
 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);
+       return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
 }
 
 
 static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256], *pos, *end;
-       int i, ret;
-
-       end = cmd + sizeof(cmd);
-       pos = cmd;
-       ret = os_snprintf(pos, end - pos, "BLACKLIST");
-       if (ret < 0 || ret >= end - pos) {
-               printf("Too long BLACKLIST 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 BLACKLIST command.\n");
-                       return -1;
-               }
-               pos += ret;
-       }
-
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
 }
 
 
 static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[256], *pos, *end;
-       int i, ret;
-
-       end = cmd + sizeof(cmd);
-       pos = cmd;
-       ret = os_snprintf(pos, end - pos, "LOG_LEVEL");
-       if (ret < 0 || ret >= end - pos) {
-               printf("Too long LOG_LEVEL 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 LOG_LEVEL command.\n");
-                       return -1;
-               }
-               pos += ret;
-       }
-
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
 }
 
 
@@ -1457,63 +1332,21 @@ static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
 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);
+       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[])
 {
-       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);
+       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[])
 {
-       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);
+       return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
 }
 
 
@@ -1527,21 +1360,7 @@ static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
 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);
+       return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
 }
 
 
@@ -1569,36 +1388,24 @@ static void wpa_cli_show_network_variables(void)
 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) {
+       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);
+       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[])
 {
-       char cmd[256];
-       int res;
-
        if (argc == 0) {
                wpa_cli_show_network_variables();
                return 0;
@@ -1610,13 +1417,39 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
                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 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_ctrl_command(ctrl, cmd);
+
+       return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
 }
 
 
@@ -1643,7 +1476,7 @@ static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
 
 static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       return wpa_ctrl_command(ctrl, "SCAN");
+       return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
 }
 
 
@@ -1656,21 +1489,7 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
 
 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);
+       return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
 }
 
 
@@ -1692,9 +1511,6 @@ static char ** wpa_cli_complete_bss(const char *str, int pos)
 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
-       char cmd[64];
-       int res;
-
        if (argc < 1 || argc > 2) {
                printf("Invalid GET_CAPABILITY command: need either one or "
                       "two arguments\n");
@@ -1707,13 +1523,7 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
                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);
+       return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
 }
 
 
@@ -1793,20 +1603,7 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
 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);
+       return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
 }
 
 
@@ -1820,14 +1617,7 @@ static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
 #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);
+       return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
 }
 
 
@@ -1843,7 +1633,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
                return -1;
        }
        len = sizeof(buf) - 1;
-       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+       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);
@@ -1854,7 +1644,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
        }
 
        buf[len] = '\0';
-       if (memcmp(buf, "FAIL", 4) == 0)
+       if (os_memcmp(buf, "FAIL", 4) == 0)
                return -1;
        printf("%s", buf);
 
@@ -1879,6 +1669,20 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
        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 */
 
 
@@ -1902,43 +1706,43 @@ static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 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);
+       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[])
 {
-       char cmd[128];
-       int res;
+       return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
+}
 
-       if (argc == 0)
-               return wpa_ctrl_command(ctrl, "P2P_FIND");
 
-       if (argc > 1)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %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 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;
 }
 
 
@@ -1952,33 +1756,7 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc < 2) {
-               printf("Invalid P2P_CONNECT command: needs at least two "
-                      "arguments (address and pbc/PIN)\n");
-               return -1;
-       }
-
-       if (argc > 4)
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_CONNECT %s %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3],
-                                 argv[4]);
-       else if (argc > 3)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       else if (argc > 2)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %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);
+       return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
 }
 
 
@@ -2000,37 +1778,14 @@ static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
 static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
                                  char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc == 0)
-               return wpa_ctrl_command(ctrl, "P2P_LISTEN");
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_LISTEN %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid P2P_GROUP_REMOVE command: needs one argument "
-                      "(interface name)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_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);
+       return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
 }
 
 
@@ -2052,31 +1807,13 @@ static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
 static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
                                        char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc == 0)
-               return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD");
-
-       if (argc > 1)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s",
-                                 argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[128];
-       int res;
-
        if (argc != 2 && argc != 3) {
                printf("Invalid P2P_PROV_DISC command: needs at least "
                       "two arguments, address and config method\n"
@@ -2084,16 +1821,7 @@ static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       if (argc == 3)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %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);
+       return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
 }
 
 
@@ -2108,7 +1836,6 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
                                         char *argv[])
 {
        char cmd[4096];
-       int res;
 
        if (argc != 2 && argc != 4) {
                printf("Invalid P2P_SERV_DISC_REQ command: needs two "
@@ -2118,16 +1845,8 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       if (argc == 4)
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_SERV_DISC_REQ %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ %s %s",
-                                 argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
                return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
 }
 
@@ -2135,21 +1854,7 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
                                                int argc, char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid P2P_SERV_DISC_CANCEL_REQ command: needs one "
-                      "argument (pending request identifier)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_CANCEL_REQ %s",
-                         argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
 }
 
 
@@ -2184,21 +1889,7 @@ static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
                                              int argc, char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid P2P_SERV_DISC_EXTERNAL command: needs one "
-                      "argument (external processing: 0/1)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_EXTERNAL %s",
-                         argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
 }
 
 
@@ -2266,60 +1957,20 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
                                  int argc, char *argv[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid P2P_REJECT command: needs one argument "
-                      "(peer address)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_REJECT %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[128];
-       int res;
-
-       if (argc < 1) {
-               printf("Invalid P2P_INVITE command: needs at least one "
-                      "argument\n");
-               return -1;
-       }
-
-       if (argc > 2)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else if (argc > 1)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char buf[64];
-       if (argc != 1) {
-               printf("Invalid 'p2p_peer' command - exactly one argument, "
-                      "P2P peer device address, is required.\n");
-               return -1;
-       }
-       os_snprintf(buf, sizeof(buf), "P2P_PEER %s", argv[0]);
-       return wpa_ctrl_command(ctrl, buf);
+       return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
 }
 
 
@@ -2349,7 +2000,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
        if (ctrl_conn == NULL)
                return -1;
        len = sizeof(buf) - 1;
-       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+       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);
@@ -2360,7 +2011,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
        }
 
        buf[len] = '\0';
-       if (memcmp(buf, "FAIL", 4) == 0)
+       if (os_memcmp(buf, "FAIL", 4) == 0)
                return -1;
 
        pos = buf;
@@ -2395,20 +2046,7 @@ static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       char cmd[100];
-       int res;
-
-       if (argc != 2) {
-               printf("Invalid P2P_SET command: needs two arguments (field, "
-                      "value)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_SET %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);
+       return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
 }
 
 
@@ -2428,48 +2066,57 @@ static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
                                       char *argv[])
 {
-       char cmd[100];
-       int res;
+       return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
+}
 
-       if (argc != 1) {
-               printf("Invalid P2P_UNAUTHORIZE command: needs one argument "
-                      "(peer address)\n");
+
+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;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %s", argv[0]);
+       return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
+}
 
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+
+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;
+       }
 
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
 }
 
 
-static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
-                                       char *argv[])
+#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 != 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");
+       if (argc != 1 && argc != 2) {
+               printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+                      "arguments (subelem, hexdump)\n");
                return -1;
        }
 
-       if (argc == 4)
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_PRESENCE_REQ %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       else if (argc == 2)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ");
+       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';
@@ -2477,33 +2124,26 @@ static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
-                                     char *argv[])
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
 {
        char cmd[100];
        int res;
 
-       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");
+       if (argc != 1) {
+               printf("Invalid WFD_SUBELEM_GET command: needs one "
+                      "argument (subelem)\n");
                return -1;
        }
 
-       if (argc == 2)
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN %s %s",
-                                 argv[0], argv[1]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN");
+       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_P2P */
+#endif /* CONFIG_WIFI_DISPLAY */
 
 
 #ifdef CONFIG_INTERWORKING
@@ -2524,142 +2164,93 @@ static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
                                           char *argv[])
 {
-       char cmd[100];
-       int res;
-
-       if (argc == 0)
-               return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
-
-       res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[100];
-       int res;
+       return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
+}
 
-       if (argc != 1) {
-               printf("Invalid INTERWORKING_CONNECT commands: needs one "
-                      "argument (BSSID)\n");
-               return -1;
-       }
 
-       res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %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_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_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
 {
-       char cmd[100];
-       int res;
+       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 != 2) {
-               printf("Invalid ANQP_GET command: needs two arguments "
-                      "(addr and info id list)\n");
+       if (argc == 0) {
+               printf("Command needs one or two arguments (dst mac addr and "
+                      "optional home realm)\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
-                         argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
+                     argc, argv) < 0)
                return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
+
        return wpa_ctrl_command(ctrl, cmd);
 }
-#endif /* CONFIG_INTERWORKING */
+
+#endif /* CONFIG_HS20 */
 
 
 static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
                                       char *argv[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid STA_AUTOCONNECT command: needs one argument "
-                      "(0/1 = disable/enable automatic reconnection)\n");
-               return -1;
-       }
-       res = os_snprintf(cmd, sizeof(cmd), "STA_AUTOCONNECT %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long STA_AUTOCONNECT command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid TDLS_DISCOVER command: needs one argument "
-                      "(Peer STA MAC address)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long TDLS_DISCOVER command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid TDLS_SETUP command: needs one argument "
-                      "(Peer STA MAC address)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long TDLS_SETUP command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       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[])
 {
-       char cmd[256];
-       int res;
-
-       if (argc != 1) {
-               printf("Invalid TDLS_TEARDOWN command: needs one argument "
-                      "(Peer STA MAC address)\n");
-               return -1;
-       }
-
-       res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long TDLS_TEARDOWN command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
 }
 
 
@@ -2670,6 +2261,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+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[])
 {
@@ -2677,6 +2275,49 @@ static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+#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);
+}
+
+
+static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, 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]);
+}
+
+
+static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "FLUSH");
+}
+
+
 enum wpa_cli_cmd_flags {
        cli_cmd_flag_none               = 0x00,
        cli_cmd_flag_sensitive          = 0x01
@@ -2685,343 +2326,448 @@ enum wpa_cli_cmd_flags {
 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,
+       { "status", wpa_cli_cmd_status, NULL,
          cli_cmd_flag_none,
          "[verbose] = get current WPA/EAPOL/EAP status" },
-       { "ping", wpa_cli_cmd_ping,
+       { "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,
+       { "relog", wpa_cli_cmd_relog, NULL,
          cli_cmd_flag_none,
          "= re-open log-file (allow rolling logs)" },
-       { "note", wpa_cli_cmd_note,
+       { "note", wpa_cli_cmd_note, NULL,
          cli_cmd_flag_none,
          "<text> = add a note to wpa_supplicant debug log" },
-       { "mib", wpa_cli_cmd_mib,
+       { "mib", wpa_cli_cmd_mib, NULL,
          cli_cmd_flag_none,
          "= get MIB variables (dot1x, dot11)" },
-       { "help", wpa_cli_cmd_help,
+       { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
          cli_cmd_flag_none,
-         "= show this usage help" },
-       { "interface", wpa_cli_cmd_interface,
+         "[command] = show usage help" },
+       { "interface", wpa_cli_cmd_interface, NULL,
          cli_cmd_flag_none,
          "[ifname] = show interfaces/select interface" },
-       { "level", wpa_cli_cmd_level,
+       { "level", wpa_cli_cmd_level, NULL,
          cli_cmd_flag_none,
          "<debug level> = change debug level" },
-       { "license", wpa_cli_cmd_license,
+       { "license", wpa_cli_cmd_license, NULL,
          cli_cmd_flag_none,
          "= show full wpa_cli license" },
-       { "quit", wpa_cli_cmd_quit,
+       { "quit", wpa_cli_cmd_quit, NULL,
          cli_cmd_flag_none,
          "= exit wpa_cli" },
-       { "set", wpa_cli_cmd_set,
+       { "set", wpa_cli_cmd_set, wpa_cli_complete_set,
          cli_cmd_flag_none,
          "= set variables (shows list of variables when run without "
          "arguments)" },
-       { "get", wpa_cli_cmd_get,
+       { "get", wpa_cli_cmd_get, NULL,
          cli_cmd_flag_none,
          "<name> = get information" },
-       { "logon", wpa_cli_cmd_logon,
+       { "logon", wpa_cli_cmd_logon, NULL,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logon" },
-       { "logoff", wpa_cli_cmd_logoff,
+       { "logoff", wpa_cli_cmd_logoff, NULL,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logoff" },
-       { "pmksa", wpa_cli_cmd_pmksa,
+       { "pmksa", wpa_cli_cmd_pmksa, NULL,
          cli_cmd_flag_none,
          "= show PMKSA cache" },
-       { "reassociate", wpa_cli_cmd_reassociate,
+       { "reassociate", wpa_cli_cmd_reassociate, NULL,
          cli_cmd_flag_none,
          "= force reassociation" },
-       { "preauthenticate", wpa_cli_cmd_preauthenticate,
+       { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<BSSID> = force preauthentication" },
-       { "identity", wpa_cli_cmd_identity,
+       { "identity", wpa_cli_cmd_identity, NULL,
          cli_cmd_flag_none,
          "<network id> <identity> = configure identity for an SSID" },
-       { "password", wpa_cli_cmd_password,
+       { "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,
+       { "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,
+       { "pin", wpa_cli_cmd_pin, NULL,
          cli_cmd_flag_sensitive,
          "<network id> <pin> = configure pin for an SSID" },
-       { "otp", wpa_cli_cmd_otp,
+       { "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,
+       { "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,
+       { "bssid", wpa_cli_cmd_bssid, NULL,
          cli_cmd_flag_none,
          "<network id> <BSSID> = set preferred BSSID for an SSID" },
-       { "blacklist", wpa_cli_cmd_blacklist,
+       { "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,
+       { "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,
+       { "list_networks", wpa_cli_cmd_list_networks, NULL,
          cli_cmd_flag_none,
          "= list configured networks" },
-       { "select_network", wpa_cli_cmd_select_network,
+       { "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,
+       { "enable_network", wpa_cli_cmd_enable_network, NULL,
          cli_cmd_flag_none,
          "<network id> = enable a network" },
-       { "disable_network", wpa_cli_cmd_disable_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,
+       { "add_network", wpa_cli_cmd_add_network, NULL,
          cli_cmd_flag_none,
          "= add a network" },
-       { "remove_network", wpa_cli_cmd_remove_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,
+       { "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,
+       { "get_network", wpa_cli_cmd_get_network, NULL,
          cli_cmd_flag_none,
          "<network id> <variable> = get network variables" },
-       { "save_config", wpa_cli_cmd_save_config,
+       { "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,
+       { "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,
+       { "reconnect", wpa_cli_cmd_reconnect, NULL,
          cli_cmd_flag_none,
          "= like reassociate, but only takes effect if already disconnected"
        },
-       { "scan", wpa_cli_cmd_scan,
+       { "scan", wpa_cli_cmd_scan, NULL,
          cli_cmd_flag_none,
          "= request new BSS scan" },
-       { "scan_results", wpa_cli_cmd_scan_results,
+       { "scan_results", wpa_cli_cmd_scan_results, NULL,
          cli_cmd_flag_none,
          "= get latest scan results" },
-       { "bss", wpa_cli_cmd_bss,
+       { "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,
+       { "get_capability", wpa_cli_cmd_get_capability, NULL,
          cli_cmd_flag_none,
-         "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
-       { "reconfigure", wpa_cli_cmd_reconfigure,
+         "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
+         "= 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,
+       { "terminate", wpa_cli_cmd_terminate, NULL,
          cli_cmd_flag_none,
          "= terminate wpa_supplicant" },
-       { "interface_add", wpa_cli_cmd_interface_add,
+       { "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,
+       { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
          cli_cmd_flag_none,
          "<ifname> = removes the interface" },
-       { "interface_list", wpa_cli_cmd_interface_list,
+       { "interface_list", wpa_cli_cmd_interface_list, NULL,
          cli_cmd_flag_none,
          "= list available interfaces" },
-       { "ap_scan", wpa_cli_cmd_ap_scan,
+       { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
          cli_cmd_flag_none,
          "<value> = set ap_scan parameter" },
-       { "scan_interval", wpa_cli_cmd_scan_interval,
+       { "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,
+       { "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,
+       { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
          cli_cmd_flag_none,
          "<value> = set BSS expiration scan count parameter" },
-       { "stkstart", wpa_cli_cmd_stkstart,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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, cli_cmd_flag_none,
+       { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
          "Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
-       { "wps_oob", wpa_cli_cmd_wps_oob,
+#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_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
+         cli_cmd_flag_none,
+         "<WPS|NDEF> = build configuration token" },
+       { "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,
-         "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
-       { "wps_reg", wpa_cli_cmd_wps_reg,
+         "<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" },
+       { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
+         cli_cmd_flag_none,
+         "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
+         "NFC handover" },
+#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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
-       { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
+#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,
+       { "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,
+       { "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, cli_cmd_flag_none,
+       { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
          "= notification of suspend/hibernate" },
-       { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+       { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
          "= notification of resume/thaw" },
-       { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+       { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
          "= drop SA without deauth/disassoc (test command)" },
-       { "roam", wpa_cli_cmd_roam,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
-         "<addr> <\"pbc\"|PIN> = connect to a P2P Devices" },
-       { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
-         "= add a new P2P group (local end as GO)" },
-       { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
+       { "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,
+       { "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,
-         cli_cmd_flag_none,
+         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,
-         cli_cmd_flag_none,
+         NULL, cli_cmd_flag_none,
          "<id> = cancel pending service discovery request" },
-       { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "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,
+       { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
          cli_cmd_flag_none,
          "<cmd> [peer=addr] = invite peer" },
-       { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
          "= flush P2P state" },
-       { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+       { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
          "= cancel P2P group formation" },
-       { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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, cli_cmd_flag_none,
+       { "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,
+       { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
          cli_cmd_flag_none,
          "[auto] = perform Interworking network selection" },
        { "interworking_connect", wpa_cli_cmd_interworking_connect,
-         cli_cmd_flag_none,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
          "<BSSID> = connect using Interworking credentials" },
-       { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+       { "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 */
-       { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+#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,
+       { "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,
+       { "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,
+       { "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,
+       { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
          cli_cmd_flag_none,
          "= get signal parameters" },
-       { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+       { "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" },
-       { NULL, NULL, cli_cmd_flag_none, NULL }
+#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" },
+       { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
+         "<query reason> = Send BSS Transition Management Query" },
+#endif /* CONFIG_WNM */
+       { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
+         "<params..> = Sent unprocessed command" },
+       { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
+         "= flush wpa_supplicant state" },
+       { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
 
@@ -3043,12 +2789,14 @@ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
 }
 
 
-static void print_help(void)
+static void print_help(const char *cmd)
 {
        int n;
        printf("commands:\n");
-       for (n = 0; wpa_cli_commands[n].cmd; n++)
-               print_cmd_help(&wpa_cli_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], "  ");
+       }
 }
 
 
@@ -3077,9 +2825,12 @@ static char ** wpa_list_cmd_list(void)
 {
        char **res;
        int i, count;
+       struct cli_txt_entry *e;
 
        count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
-       res = os_zalloc(count * sizeof(char *));
+       count += dl_list_len(&p2p_groups);
+       count += dl_list_len(&ifnames);
+       res = os_calloc(count + 1, sizeof(char *));
        if (res == NULL)
                return NULL;
 
@@ -3089,6 +2840,22 @@ static char ** wpa_list_cmd_list(void)
                        break;
        }
 
+       dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+               size_t len = 8 + os_strlen(e->txt);
+               res[i] = os_malloc(len);
+               if (res[i] == NULL)
+                       break;
+               os_snprintf(res[i], len, "ifname=%s", e->txt);
+               i++;
+       }
+
+       dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+               res[i] = os_strdup(e->txt);
+               if (res[i] == NULL)
+                       break;
+               i++;
+       }
+
        return res;
 }
 
@@ -3098,19 +2865,11 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
 {
        int i;
 
-       if (os_strcasecmp(cmd, "bss") == 0)
-               return wpa_cli_complete_bss(str, pos);
-#ifdef CONFIG_P2P
-       if (os_strcasecmp(cmd, "p2p_connect") == 0)
-               return wpa_cli_complete_p2p_connect(str, pos);
-       if (os_strcasecmp(cmd, "p2p_peer") == 0)
-               return wpa_cli_complete_p2p_peer(str, pos);
-       if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
-               return wpa_cli_complete_p2p_group_remove(str, pos);
-#endif /* CONFIG_P2P */
-
        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();
@@ -3128,6 +2887,14 @@ static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
        const char *end;
        char *cmd;
 
+       if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+               end = os_strchr(str, ' ');
+               if (end && pos > end - str) {
+                       pos -= end - str + 1;
+                       str = end + 1;
+               }
+       }
+
        end = os_strchr(str, ' ');
        if (end == NULL || str + pos < end)
                return wpa_list_cmd_list();
@@ -3149,6 +2916,16 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
        int count;
        int ret = 0;
 
+       if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+               ifname_prefix = argv[0] + 7;
+               argv = &argv[1];
+               argc--;
+       } else
+               ifname_prefix = NULL;
+
+       if (argc == 0)
+               return -1;
+
        count = 0;
        cmd = wpa_cli_commands;
        while (cmd->cmd) {
@@ -3296,6 +3073,8 @@ static void wpa_cli_action_process(const char *msg)
                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, ESS_DISASSOC_IMMINENT)) {
+               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;
@@ -3314,7 +3093,14 @@ static void wpa_cli_action_cb(char *msg, size_t len)
 static void wpa_cli_reconnect(void)
 {
        wpa_cli_close_connection();
-       wpa_cli_open_connection(ctrl_ifname, 1);
+       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();
+       }
 }
 
 
@@ -3350,7 +3136,6 @@ static void cli_event(const char *str)
                return;
        }
 
-#ifdef CONFIG_P2P
        if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
                s = os_strstr(start, " p2p_dev_addr=");
                if (s == NULL)
@@ -3382,7 +3167,33 @@ static void cli_event(const char *str)
                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;
 }
 
 
@@ -3406,6 +3217,9 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
                                        printf("\r%s\n", buf);
                                        edit_redraw();
                                }
+
+                               if (interactive && check_terminating(buf) > 0)
+                                       return;
                        }
                } else {
                        printf("Could not read pending message.\n");
@@ -3465,12 +3279,6 @@ static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-static void wpa_cli_eloop_terminate(int sig, void *signal_ctx)
-{
-       eloop_terminate();
-}
-
-
 static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
 {
        wpa_cli_recv_pending(mon_conn, 0);
@@ -3493,11 +3301,18 @@ static void wpa_cli_edit_eof_cb(void *ctx)
 }
 
 
-static void wpa_cli_interactive(void)
+static int warning_displayed = 0;
+static char *hfile = NULL;
+static int edit_started = 0;
+
+static void start_edit(void)
 {
-       char *home, *hfile = NULL;
+       char *home;
+       char *ps = NULL;
 
-       printf("\nInteractive mode\n\n");
+#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) {
@@ -3508,17 +3323,122 @@ static void wpa_cli_interactive(void)
                        os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
        }
 
-       eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL);
-       edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
-                 wpa_cli_edit_completion_cb, NULL, hfile);
+       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 update_bssid_list(struct wpa_ctrl *ctrl)
+{
+       char buf[4096];
+       size_t len = sizeof(buf);
+       int ret;
+       char *cmd = "BSS RANGE=ALL MASK=0x2";
+       char *pos, *end;
+
+       if (ctrl == NULL)
+               return;
+       ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+       if (ret < 0)
+               return;
+       buf[len] = '\0';
+
+       pos = buf;
+       while (pos) {
+               pos = os_strstr(pos, "bssid=");
+               if (pos == NULL)
+                       break;
+               pos += 6;
+               end = os_strchr(pos, '\n');
+               if (end == NULL)
+                       break;
+               *end = '\0';
+               cli_txt_list_add(&bsses, pos);
+               pos = end + 1;
+       }
+}
+
+
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+       char buf[4096];
+       size_t len = sizeof(buf);
+       int ret;
+       char *cmd = "INTERFACES";
+       char *pos, *end;
+       char txt[200];
+
+       cli_txt_list_flush(&ifnames);
+
+       if (ctrl == NULL)
+               return;
+       ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+       if (ret < 0)
+               return;
+       buf[len] = '\0';
+
+       pos = buf;
+       while (pos) {
+               end = os_strchr(pos, '\n');
+               if (end == NULL)
+                       break;
+               *end = '\0';
+               ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+               if (ret > 0 && ret < (int) sizeof(txt))
+                       cli_txt_list_add(&ifnames, txt);
+               pos = end + 1;
+       }
+}
+
+
+static void try_connection(void *eloop_ctx, void *timeout_ctx)
+{
+       if (ctrl_conn)
+               goto done;
+
+       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;
+       }
+
+       update_bssid_list(ctrl_conn);
+
+       if (warning_displayed)
+               printf("Connection established.\n");
 
+done:
+       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);
-       edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
+       cli_txt_list_flush(&ifnames);
+       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();
@@ -3577,10 +3497,10 @@ static void wpa_cli_cleanup(void)
        os_program_deinit();
 }
 
-static void wpa_cli_terminate(int sig)
+
+static void wpa_cli_terminate(int sig, void *ctx)
 {
-       wpa_cli_cleanup();
-       exit(0);
+       eloop_terminate();
 }
 
 
@@ -3623,7 +3543,7 @@ static char * wpa_cli_get_default_ifname(void)
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-       char buf[2048], *pos;
+       char buf[4096], *pos;
        size_t len;
        struct wpa_ctrl *ctrl;
        int ret;
@@ -3650,7 +3570,6 @@ static char * wpa_cli_get_default_ifname(void)
 
 int main(int argc, char *argv[])
 {
-       int warning_displayed = 0;
        int c;
        int daemonize = 0;
        int ret = 0;
@@ -3713,41 +3632,44 @@ int main(int argc, char *argv[])
                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");
+                       fprintf(stderr, "Failed to connect to wpa_supplicant "
+                               "global interface: %s  error: %s\n",
+                               global, strerror(errno));
                        return -1;
                }
+
+               if (interactive) {
+                       update_ifnames(ctrl_conn);
+                       mon_conn = wpa_ctrl_open(global);
+                       if (mon_conn) {
+                               if (wpa_ctrl_attach(mon_conn) == 0) {
+                                       wpa_cli_attached = 1;
+                                       eloop_register_read_sock(
+                                               wpa_ctrl_get_fd(mon_conn),
+                                               wpa_cli_mon_receive,
+                                               NULL, NULL);
+                               } else {
+                                       printf("Failed to open monitor "
+                                              "connection through global "
+                                              "control interface\n");
+                               }
+                       }
+               }
        }
 
-#ifndef _WIN32_WCE
-       signal(SIGINT, wpa_cli_terminate);
-       signal(SIGTERM, wpa_cli_terminate);
-#endif /* _WIN32_WCE */
+       eloop_register_signal_terminate(wpa_cli_terminate, NULL);
 
        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;
-               }
+               wpa_cli_interactive();
        } else {
                if (!global &&
                    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
-                       perror("Failed to connect to wpa_supplicant - "
-                              "wpa_ctrl_open");
+                       fprintf(stderr, "Failed to connect to non-global "
+                               "ctrl_ifname: %s  error: %s\n",
+                               ctrl_ifname, strerror(errno));
                        return -1;
                }
 
@@ -3760,17 +3682,16 @@ int main(int argc, char *argv[])
                                return -1;
                        }
                }
-       }
 
-       if (daemonize && os_daemonize(pid_file))
-               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]);
+               if (action_file)
+                       wpa_cli_action(ctrl_conn);
+               else
+                       ret = wpa_request(ctrl_conn, argc - optind,
+                                         &argv[optind]);
+       }
 
        os_free(ctrl_ifname);
        eloop_destroy();
diff --git a/wpa_supplicant/wpa_gui-qt4/.gitignore b/wpa_supplicant/wpa_gui-qt4/.gitignore
new file mode 100644 (file)
index 0000000..da818cb
--- /dev/null
@@ -0,0 +1,4 @@
+.moc
+.obj
+.ui
+qrc_icons.cpp
index 88d4603..27cbdd6 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - AddInterface class
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 9d9476a..1b4c98d 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - AddInterface class
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef ADDINTERFACE_H
index 1eb0b7b..a36085d 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - EventHistory class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <QHeaderView>
index 40dff6d..3c01aa8 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - EventHistory class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef EVENTHISTORY_H
diff --git a/wpa_supplicant/wpa_gui-qt4/lang/.gitignore b/wpa_supplicant/wpa_gui-qt4/lang/.gitignore
new file mode 100644 (file)
index 0000000..8df47d5
--- /dev/null
@@ -0,0 +1 @@
+*.qm
index 6170b15..73d677c 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - Application startup
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifdef CONFIG_NATIVE_WINDOWS
index fe50a8d..737c41c 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - NetworkConfig class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 0ceeb41..429b648 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - NetworkConfig class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef NETWORKCONFIG_H
index 65bb17d..f5aa9f7 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - Peers class
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index a715395..bac77dc 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - Peers class
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef PEERS_H
index f75f02a..063347e 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - ScanResults class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 2c4a1b0..4a5842c 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - ScanResults class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SCANRESULTS_H
index f2688d5..2bba582 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - SignalBar class
  * Copyright (c) 2011, Kel Modderman <kel@otaku42.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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 3d5dec1..37da5dd 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - SignalBar class
  * Copyright (c) 2011, Kel Modderman <kel@otaku42.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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SIGNALBAR_H
index 1ca98d9..420e0be 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - StringQuery class
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 1b68217..9d6bffd 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - StringQuery class
  * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef STRINGQUERY_H
index 345f965..ba4c9f4 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - UserDataRequest class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "userdatarequest.h"
index 2b6e837..0d9dbfc 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - UserDataRequest class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef USERDATAREQUEST_H
index 97bf5ac..6bba8d2 100644 (file)
@@ -2,26 +2,16 @@
  * wpa_gui - WpaGui class
  * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
 #ifdef CONFIG_NATIVE_WINDOWS
 #include <windows.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #include <cstdio>
+#include <unistd.h>
 #include <QMessageBox>
 #include <QCloseEvent>
 #include <QImageReader>
@@ -719,17 +709,13 @@ void WpaGui::helpContents()
 void WpaGui::helpAbout()
 {
        QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-                          "Copyright (c) 2003-2011,\n"
+                          "Copyright (c) 2003-2013,\n"
                           "Jouni Malinen <j@w1.fi>\n"
                           "and contributors.\n"
                           "\n"
-                          "This program is free software. You can\n"
-                          "distribute it and/or modify it under the terms "
-                          "of\n"
-                          "the GNU General Public License version 2.\n"
-                          "\n"
-                          "Alternatively, this software may be distributed\n"
-                          "under the terms of the BSD license.\n"
+                          "This software may be distributed under\n"
+                          "the terms of the BSD license.\n"
+                          "See README for more details.\n"
                           "\n"
                           "This product includes software developed\n"
                           "by the OpenSSL Project for use in the\n"
index 2e1af8e..340286c 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - WpaGui class
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPAGUI_H
index 4950b21..8f2fcdc 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - WpaMsg class for storing event messages
  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPAMSG_H
index 67465aa..9b568f0 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - ASCII passphrase to WPA PSK tool
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -58,7 +52,7 @@ int main(int argc, char *argv[])
                return 1;
        }
 
-       pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
+       pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
 
        printf("network={\n");
        printf("\tssid=\"%s\"\n", ssid);
index c8854da..4afaae9 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / privileged helper program
  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -579,13 +573,11 @@ wpa_priv_interface_init(const char *dir, const char *params)
        iface->fd = -1;
 
        len = pos - params;
-       iface->driver_name = os_malloc(len + 1);
+       iface->driver_name = dup_binstr(params, len);
        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,
@@ -649,7 +641,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
                        }
                        if (bind(iface->fd, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               perror("wpa-priv-iface-init: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
index d04d32b..d9f8616 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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
 #include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.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 "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"
+#include "wnm_sta.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2013, Jouni Malinen <j@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"
+"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"
@@ -71,22 +68,9 @@ const char *wpa_supplicant_license =
 #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"
+"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"
@@ -144,8 +128,8 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 }
 
 
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
-                                          struct wpa_ssid *ssid)
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+                                   struct wpa_ssid *ssid)
 {
        u8 key[32];
        size_t keylen;
@@ -173,6 +157,11 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
                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);
@@ -192,68 +181,6 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
        return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
 }
 
-/*
- * Jan, 17th 2012. TIZEN
- * A supplicant tries to scan infinitely after auth timeout is occured.
- * However, it caused a connman's side effect.
- * Thus it should be changed like followings.
- * First, a select network function performs associating without scan, which is our modification.
- * Second, if an auth timeout is occured, the supplicant tries full scan and tries to associate again.
- * Finally, if the supplicant encounters second timeout, it would be stopped with no more scan.
- */
-
-/*
- * Start
- */
-#if defined TIZEN_EXT
-static int wpa_supplicant_is_set_scan_ssid(struct wpa_supplicant *wpa_s)
-{
-       int ret = -1;
-       struct wpa_ssid *start;
-
-       if (wpa_s == NULL)
-               return -1;
-       if (wpa_s->conf == NULL)
-               return -1;
-       if (wpa_s->conf->ssid == NULL)
-               return -1;
-
-       start = wpa_s->conf->ssid;
-
-       while (start) {
-               if (start->scan_ssid != 0) {
-                       ret = 0;
-                       break;
-               }
-               start = start->next;
-       }
-
-       return ret;
-
-}
-
-static void wpa_supplicant_unset_scan_ssid(struct wpa_supplicant *wpa_s)
-{
-       struct wpa_ssid *start;
-
-       if (wpa_s == NULL)
-               return;
-       if (wpa_s->conf == NULL)
-               return;
-       if (wpa_s->conf->ssid == NULL)
-               return;
-
-       start = wpa_s->conf->ssid;
-
-       while (start) {
-               start->scan_ssid = 0;
-               start = start->next;
-       }
-}
-/*
- * Finish
- */
-#endif
 
 static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
 {
@@ -264,34 +191,8 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
        wpa_blacklist_add(wpa_s, bssid);
-
-#if defined TIZEN_EXT
-       /*
-        * Jan, 17th 2012. TIZEN
-        * A supplicant tries to scan infinitely after auth timeout is occured.
-        * However, it caused a connman's side effect.
-        * Thus it should be changed like followings.
-        * First, a select network function performs associating without scan, which is our modification.
-        * Second, if an auth timeout is occured, the supplicant tries full scan and tries to associate again.
-        * Finally, if the supplicant encounters second timeout, it would be stopped with no more scan.
-        */
-
-       if (wpa_s->key_mgmt != KEY_MGMT_WPS) {
-               if (wpa_supplicant_is_set_scan_ssid(wpa_s) == -1) {
-                       wpa_sm_notify_disassoc(wpa_s->wpa);
-                       wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-                       wpa_s->reassociate = 0;
-                       wpa_s->disconnected = 1;
-                       return;
-               }
-
-               wpa_supplicant_unset_scan_ssid(wpa_s);
-       }
-#else
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-#endif
-
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        wpa_s->reassociate = 1;
 
        /*
@@ -299,6 +200,8 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
         * So, wait a second until scanning again.
         */
        wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+       wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -458,7 +361,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
-static void free_hw_features(struct wpa_supplicant *wpa_s)
+void free_hw_features(struct wpa_supplicant *wpa_s)
 {
        int i;
        if (wpa_s->hw.modes == NULL)
@@ -477,6 +380,7 @@ static void free_hw_features(struct wpa_supplicant *wpa_s)
 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);
@@ -488,21 +392,18 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                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;
 
+       os_free(wpa_s->confanother);
+       wpa_s->confanother = NULL;
+
        wpa_sm_set_eapol(wpa_s->wpa, NULL);
        eapol_sm_deinit(wpa_s->eapol);
        wpa_s->eapol = NULL;
@@ -561,6 +462,27 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        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);
+#ifdef CONFIG_WNM
+       wnm_deallocate_memory(wpa_s);
+#endif /* CONFIG_WNM */
+
+       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;
 }
 
 
@@ -662,8 +584,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
                         * optimization, so the initial connection is not
                         * affected.
                         */
-               } else
+               } 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;
 }
@@ -680,6 +610,29 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
 #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
@@ -701,17 +654,28 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                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;
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+#ifdef TIZEN_EXT_P2P
+               if (wpa_s->ifname && (os_strcmp(wpa_s->ifname , "p2p-wlan0-0") == 0))
+                       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 : "");
+                       wpa_msg(wpa_s->parent, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+#else
                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)",
+#endif
+                       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_s->reassociated_connection = 1;
                wpa_drv_set_operstate(wpa_s, 1);
 #ifndef IEEE8021X_EAPOL
                wpa_drv_set_supp_port(wpa_s, 1);
@@ -721,20 +685,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpas_p2p_completed(wpa_s);
 #endif /* CONFIG_P2P */
 
-#if defined TIZEN_EXT
-               /*
-                * Nov, 2nd. 2011. TIZEN
-                * After association is completed, scan should be set full scan.
-                */
-               if (wpa_s->conf->ssid != NULL) {
-                       struct wpa_ssid *start = wpa_s->conf->ssid;
-                       while (start) {
-                               start->scan_ssid = 0;
-                               start = start->next;
-                       }
-               }
-#endif
-
+               sme_sched_obss_scan(wpa_s, 1);
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -742,9 +693,21 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #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;
 
+#if defined TIZEN_EXT
+       if (state == WPA_DISCONNECTED) {
+               struct wpa_ssid *ssid = wpa_s->current_ssid;
+               wpa_msg(wpa_s->parent, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnection 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
 #ifdef CONFIG_BGSCAN
        if (state == WPA_COMPLETED)
                wpa_supplicant_start_bgscan(wpa_s);
@@ -752,6 +715,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                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);
 
@@ -782,11 +751,6 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global)
 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);
 }
 
@@ -800,7 +764,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
        wpa_s->mgmt_group_cipher = 0;
        wpa_s->key_mgmt = 0;
        if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
-               wpa_s->wpa_state = WPA_DISCONNECTED;
+               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);
@@ -826,12 +790,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 
        if (wpa_s->confname == NULL)
                return -1;
-       conf = wpa_config_read(wpa_s->confname);
+       conf = wpa_config_read(wpa_s->confname, NULL);
        if (conf == NULL) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
                        "file '%s' - exiting", wpa_s->confname);
                return -1;
        }
+       wpa_config_read(wpa_s->confanother, conf);
+
        conf->changed_parameters = (unsigned int) -1;
 
        reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
@@ -879,7 +845,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        wpa_supplicant_update_config(wpa_s);
 
        wpa_supplicant_clear_status(wpa_s);
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       if (wpa_supplicant_enabled_networks(wpa_s)) {
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
        }
@@ -902,24 +868,6 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
 }
 
 
-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) {
@@ -984,7 +932,9 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-           ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+           (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");
@@ -1086,41 +1036,30 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        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_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_s->group_cipher = wpa_pick_group_cipher(sel);
+       if (wpa_s->group_cipher < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
                        "cipher");
                return -1;
        }
+       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
+               wpa_cipher_txt(wpa_s->group_cipher));
 
        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_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_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
+       if (wpa_s->pairwise_cipher < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
                        "cipher");
                return -1;
        }
+       wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
+               wpa_cipher_txt(wpa_s->pairwise_cipher));
 
        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) {
@@ -1130,6 +1069,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_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;
@@ -1162,7 +1109,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        sel = ie.mgmt_group_cipher;
-       if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+       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) {
@@ -1175,7 +1123,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
        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);
+       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)) {
@@ -1189,13 +1139,70 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
                        u8 psk[PMK_LEN];
-                       pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
-                                   bss->ssid_len, 4096, 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);
 
@@ -1203,6 +1210,70 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
+{
+       *pos = 0x00;
+
+       switch (idx) {
+       case 0: /* Bits 0-7 */
+               break;
+       case 1: /* Bits 8-15 */
+               break;
+       case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+               *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+               break;
+       case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+               if (wpa_s->conf->interworking)
+                       *pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+               break;
+       case 4: /* Bits 32-39 */
+               break;
+       case 5: /* Bits 40-47 */
+               break;
+       case 6: /* Bits 48-55 */
+               break;
+       }
+}
+
+
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+       u8 *pos = buf;
+       u8 len = 4, i;
+
+       if (len < wpa_s->extended_capa_len)
+               len = wpa_s->extended_capa_len;
+
+       *pos++ = WLAN_EID_EXT_CAPAB;
+       *pos++ = len;
+       for (i = 0; i < len; i++, pos++) {
+               wpas_ext_capab_byte(wpa_s, pos, i);
+
+               if (i < wpa_s->extended_capa_len) {
+                       *pos &= ~wpa_s->extended_capa_mask[i];
+                       *pos |= wpa_s->extended_capa[i];
+               }
+       }
+
+       while (len > 0 && buf[1 + len] == 0) {
+               len--;
+               buf[1] = len;
+       }
+       if (len == 0)
+               return 0;
+
+       return 2 + len;
+}
+
+
 /**
  * wpa_supplicant_associate - Request association
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1221,9 +1292,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        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);
@@ -1238,7 +1314,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                "mode");
                        return;
                }
-               wpa_supplicant_create_ap(wpa_s, ssid);
+               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 "
@@ -1289,7 +1368,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                   (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->scan_req = MANUAL_SCAN_REQ;
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
                return;
@@ -1327,11 +1406,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
-               try_opportunistic = ssid->proactive_key_caching &&
+               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)
+                                           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,
@@ -1340,6 +1420,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                "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,
@@ -1377,11 +1467,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                u8 *pos;
                size_t len;
                int res;
-               int p2p_group;
-               p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
                pos = wpa_ie + wpa_ie_len;
                len = sizeof(wpa_ie) - wpa_ie_len;
-               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+                                           ssid->p2p_group);
                if (res >= 0)
                        wpa_ie_len += res;
        }
@@ -1402,26 +1491,35 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_INTERWORKING
-       if (wpa_s->conf->interworking) {
+#ifdef CONFIG_HS20
+       if (is_hs20_network(wpa_s, ssid, bss)) {
+               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 + 6, pos, wpa_ie_len - (pos - wpa_ie));
-               wpa_ie_len += 6;
-               *pos++ = WLAN_EID_EXT_CAPAB;
-               *pos++ = 4;
-               *pos++ = 0x00;
-               *pos++ = 0x00;
-               *pos++ = 0x00;
-               *pos++ = 0x80; /* Bit 31 - Interworking */
+               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);
        }
-#endif /* CONFIG_INTERWORKING */
 
        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);
+       cipher_pairwise = wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
+       cipher_group = wpa_cipher_to_suite_driver(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)
@@ -1459,7 +1557,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        if (bss) {
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               if (!wpas_driver_bss_selection(wpa_s)) {
+               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;
                }
@@ -1467,6 +1570,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                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 */
@@ -1478,6 +1588,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        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];
@@ -1496,8 +1607,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-       params.mgmt_frame_protection = ssid->ieee80211w;
-       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+       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 &&
@@ -1518,6 +1631,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        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 "
@@ -1529,6 +1650,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                         * 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;
                }
@@ -1569,8 +1691,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                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) {
+       if (wep_keys_set &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
                /* Set static WEP keys again */
                wpa_set_wep_keys(wpa_s, ssid);
        }
@@ -1598,10 +1720,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
        struct wpa_ssid *old_ssid;
 
        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_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)
@@ -1610,6 +1730,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef TIZEN_EXT
 /**
  * wpa_supplicant_disassociate - Disassociate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1630,6 +1751,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_clear_connection(wpa_s, addr);
 }
+#endif /* TIZEN_EXT */
 
 
 /**
@@ -1644,15 +1766,66 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
        u8 *addr = NULL;
+       union wpa_event_data event;
+       int zero_addr = 0;
 
-       if (!is_zero_ether_addr(wpa_s->bssid)) {
-               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+       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;
+       }
+
+#ifdef CONFIG_TDLS
+       wpa_tdls_teardown_peers(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
+       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);
 }
 
+static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
+                                             struct wpa_ssid *ssid)
+{
+       if (!ssid || !ssid->disabled || ssid->disabled == 2)
+               return;
+
+       ssid->disabled = 0;
+       wpas_clear_temp_disabled(wpa_s, ssid, 1);
+       wpas_notify_network_enabled_changed(wpa_s, ssid);
+
+       /*
+        * Try to reassociate since there is no current configuration and a new
+        * network was made available.
+        */
+       if (!wpa_s->current_ssid)
+               wpa_s->reassociate = 1;
+}
+
 
 /**
  * wpa_supplicant_enable_network - Mark a configured network as enabled
@@ -1664,45 +1837,21 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 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;
+               for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+                       wpa_supplicant_enable_one_network(wpa_s, ssid);
+       } else
+               wpa_supplicant_enable_one_network(wpa_s, ssid);
 
-                       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);
+       if (wpa_s->reassociate) {
+               if (wpa_s->sched_scanning) {
+                       wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
+                                  "new network to scan filters");
+                       wpa_supplicant_cancel_sched_scan(wpa_s);
                }
 
-               was_disabled = ssid->disabled;
-
-               ssid->disabled = 0;
-
-               if (was_disabled != ssid->disabled)
-                       wpas_notify_network_enabled_changed(wpa_s, ssid);
+               if (wpa_supplicant_fast_associate(wpa_s) != 1)
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
        }
 }
 
@@ -1721,6 +1870,9 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
        int was_disabled;
 
        if (ssid == NULL) {
+               if (wpa_s->sched_scanning)
+                       wpa_supplicant_cancel_sched_scan(wpa_s);
+
                for (other_ssid = wpa_s->conf->ssid; other_ssid;
                     other_ssid = other_ssid->next) {
                        was_disabled = other_ssid->disabled;
@@ -1735,19 +1887,26 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
                                        wpa_s, other_ssid);
                }
                if (wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        } else if (ssid->disabled != 2) {
                if (ssid == wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
                was_disabled = ssid->disabled;
 
                ssid->disabled = 1;
 
-               if (was_disabled != ssid->disabled)
+               if (was_disabled != ssid->disabled) {
                        wpas_notify_network_enabled_changed(wpa_s, ssid);
+                       if (wpa_s->sched_scanning) {
+                               wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan "
+                                          "to remove network from filters");
+                               wpa_supplicant_cancel_sched_scan(wpa_s);
+                               wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       }
+               }
        }
 }
 
@@ -1760,18 +1919,18 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                                   struct wpa_ssid *ssid)
 {
-#if defined TIZEN_EXT
-       /*
-        * August 1st, 2011 TIZEN
-        * This part is changed to reduce associating duration.
-        */
-       struct wpa_bss *selected_bss;
-#endif
+
        struct wpa_ssid *other_ssid;
+       int disconnected = 0;
 
-       if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
-               wpa_supplicant_disassociate(
+       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
@@ -1784,6 +1943,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                        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);
@@ -1796,32 +1957,17 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (ssid)
+               wpa_s->current_ssid = ssid;
        wpa_s->connect_without_scan = NULL;
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
 
-#if defined TIZEN_EXT
-       /*
-        * August 1st, 2011 TIZEN
-        * This part is changed to reduce associating duration.
-        */
-       if ((selected_bss = wpa_bss_check_scan_res(wpa_s, ssid->ssid)) == NULL)
-       {
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-               if (ssid)
-                       wpas_notify_network_selected(wpa_s, ssid);
-       } else {
-               if (ssid)
-                       wpas_notify_network_selected(wpa_s, ssid);
-
-               wpa_supplicant_connect(wpa_s, selected_bss, ssid);
-       }
-#else
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       if (wpa_supplicant_fast_associate(wpa_s) != 1)
+               wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
 
        if (ssid)
                wpas_notify_network_selected(wpa_s, ssid);
-#endif
 }
 
 
@@ -1907,17 +2053,40 @@ int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
 
 
 /**
- * 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
+ * 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_debug_params(struct wpa_global *global, int debug_level,
-                                   int debug_timestamp, int debug_show_keys)
+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_supplicant_update_scan_int(wpa_s, 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 */
@@ -1981,14 +2150,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 
        entry = wpa_s->conf->ssid;
        while (entry) {
-               if (!entry->disabled &&
+               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 (!entry->disabled &&
+               if (!wpas_network_disabled(wpa_s, entry) &&
                    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
                    (entry->ssid == NULL || entry->ssid_len == 0) &&
                    (!entry->bssid_set ||
@@ -1996,7 +2165,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                        return entry;
 #endif /* CONFIG_WPS */
 
-               if (!entry->disabled && entry->bssid_set &&
+               if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
                    entry->ssid_len == 0 &&
                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
                        return entry;
@@ -2059,8 +2228,11 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                for (i = 0; wpa_drivers[i]; i++) {
                        if (os_strlen(wpa_drivers[i]->name) == len &&
                            os_strncmp(driver, wpa_drivers[i]->name, len) ==
-                           0)
-                               return select_driver(wpa_s, i);
+                           0) {
+                               /* First driver that succeeds wins */
+                               if (select_driver(wpa_s, i) == 0)
+                                       return 0;
+                       }
                }
 
                driver = pos + 1;
@@ -2093,17 +2265,28 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
        wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
-       if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+       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.
+                * 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");
+                       "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) {
@@ -2114,6 +2297,9 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
                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);
@@ -2188,7 +2374,10 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
                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 &
+       } else if ((!wpa_s->p2p_mgmt ||
+                   !(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+                  !(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,
@@ -2208,14 +2397,35 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
                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
@@ -2232,14 +2442,18 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
                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);
+
        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, wpa_s,
-                                             0);
+                                             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'",
@@ -2258,7 +2472,9 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        wpa_drv_flush_pmkid(wpa_s);
 
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       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,
@@ -2285,20 +2501,335 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s = os_zalloc(sizeof(*wpa_s));
        if (wpa_s == NULL)
                return NULL;
-       wpa_s->scan_req = 1;
+       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;
-#if defined TIZEN_EXT
+
+       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;
+               }
+       }
+
        /*
-        * Jan, 9th 2012. TIZEN
-        * Remove reconnect procedure after getting disassoc event
+        * If we were able to parse any values, then set mask for the MCS set.
         */
-       wpa_s->auto_reconnect_disabled = 1;
-#endif
+       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 wpa_s;
+       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 */
+
+
+#ifdef CONFIG_VHT_OVERRIDES
+void wpa_supplicant_apply_vht_overrides(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+       struct wpa_driver_associate_params *params)
+{
+       struct ieee80211_vht_capabilities *vhtcaps;
+       struct ieee80211_vht_capabilities *vhtcaps_mask;
+
+       if (!ssid)
+               return;
+
+       params->disable_vht = ssid->disable_vht;
+
+       vhtcaps = (void *) params->vhtcaps;
+       vhtcaps_mask = (void *) params->vhtcaps_mask;
+
+       if (!vhtcaps || !vhtcaps_mask)
+               return;
+
+       vhtcaps->vht_capabilities_info = ssid->vht_capa;
+       vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+
+#define OVERRIDE_MCS(i)                                                        \
+       if (ssid->vht_tx_mcs_nss_ ##i >= 0) {                           \
+               vhtcaps_mask->vht_supported_mcs_set.tx_map |=           \
+                       3 << 2 * (i - 1);                               \
+               vhtcaps->vht_supported_mcs_set.tx_map |=                \
+                       ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1);       \
+       }                                                               \
+       if (ssid->vht_rx_mcs_nss_ ##i >= 0) {                           \
+               vhtcaps_mask->vht_supported_mcs_set.rx_map |=           \
+                       3 << 2 * (i - 1);                               \
+               vhtcaps->vht_supported_mcs_set.rx_map |=                \
+                       ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1);       \
+       }
+
+       OVERRIDE_MCS(1);
+       OVERRIDE_MCS(2);
+       OVERRIDE_MCS(3);
+       OVERRIDE_MCS(4);
+       OVERRIDE_MCS(5);
+       OVERRIDE_MCS(6);
+       OVERRIDE_MCS(7);
+       OVERRIDE_MCS(8);
+}
+#endif /* CONFIG_VHT_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;
 }
 
 
@@ -2329,12 +2860,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 #else /* CONFIG_BACKEND_FILE */
                wpa_s->confname = os_strdup(iface->confname);
 #endif /* CONFIG_BACKEND_FILE */
-               wpa_s->conf = wpa_config_read(wpa_s->confname);
+               wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
                if (wpa_s->conf == NULL) {
                        wpa_printf(MSG_ERROR, "Failed to read or parse "
                                   "configuration '%s'.", wpa_s->confname);
                        return -1;
                }
+               wpa_s->confanother = os_rel2abs_path(iface->confanother);
+               wpa_config_read(wpa_s->confanother, wpa_s->conf);
 
                /*
                 * Override ctrl_interface and driver_param if set on command
@@ -2351,6 +2884,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                        wpa_s->conf->driver_param =
                                os_strdup(iface->driver_param);
                }
+
+               if (iface->p2p_mgmt && !iface->ctrl_interface) {
+                       os_free(wpa_s->conf->ctrl_interface);
+                       wpa_s->conf->ctrl_interface = NULL;
+               }
        } else
                wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
                                                     iface->driver_param);
@@ -2461,6 +2999,7 @@ next_driver:
        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;
@@ -2468,15 +3007,31 @@ next_driver:
                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;
+               wpa_s->extended_capa = capa.extended_capa;
+               wpa_s->extended_capa_mask = capa.extended_capa_mask;
+               wpa_s->extended_capa_len = capa.extended_capa_len;
        }
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
 
+       /*
+        * Only take p2p_mgmt parameters when P2P Device is supported.
+        * Doing it here as it determines whether l2_packet_init() will be done
+        * during wpa_supplicant_driver_init().
+        */
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+               wpa_s->p2p_mgmt = iface->p2p_mgmt;
+       else
+               iface->p2p_mgmt = 1;
+
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
 #ifdef CONFIG_TDLS
-       if (wpa_tdls_init(wpa_s->wpa))
+       if ((!iface->p2p_mgmt ||
+            !(wpa_s->drv_flags &
+              WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+           wpa_tdls_init(wpa_s->wpa))
                return -1;
 #endif /* CONFIG_TDLS */
 
@@ -2514,7 +3069,7 @@ next_driver:
        }
 
 #ifdef CONFIG_P2P
-       if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+       if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
                return -1;
        }
@@ -2523,13 +3078,34 @@ next_driver:
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_EAP_PROXY
+{
+       size_t len;
+       wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &len);
+       if (wpa_s->mnc_len > 0) {
+               wpa_s->imsi[len] = '\0';
+               wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+                          wpa_s->imsi, wpa_s->mnc_len);
+       } else {
+               wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+       }
+}
+#endif /* CONFIG_EAP_PROXY */
+
+       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 notify, int terminate)
 {
+       wpa_s->disconnected = 1;
        if (wpa_s->drv_priv) {
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
@@ -2540,11 +3116,34 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_cleanup(wpa_s);
 
-       if (notify)
-               wpas_notify_iface_removed(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;
+       }
+
+       os_free(wpa_s);
 }
 
 
@@ -2594,15 +3193,13 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        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);
+               wpa_supplicant_deinit_iface(wpa_s, 0, 0);
                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);
+               wpa_supplicant_deinit_iface(wpa_s, 1, 0);
                return NULL;
        }
 
@@ -2613,6 +3210,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        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;
 }
@@ -2630,7 +3228,8 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
  * %wpa_supplicant is terminated.
  */
 int wpa_supplicant_remove_iface(struct wpa_global *global,
-                               struct wpa_supplicant *wpa_s)
+                               struct wpa_supplicant *wpa_s,
+                               int terminate)
 {
        struct wpa_supplicant *prev;
 
@@ -2650,8 +3249,9 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
        if (global->p2p_group_formation == wpa_s)
                global->p2p_group_formation = NULL;
-       wpa_supplicant_deinit_iface(wpa_s, 1);
-       os_free(wpa_s);
+       if (global->p2p_invite_group == wpa_s)
+               global->p2p_invite_group = NULL;
+       wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
 
        return 0;
 }
@@ -2740,6 +3340,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        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) {
@@ -2763,6 +3371,9 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params->ctrl_interface)
                global->params.ctrl_interface =
                        os_strdup(params->ctrl_interface);
+       if (params->ctrl_interface_group)
+               global->params.ctrl_interface_group =
+                       os_strdup(params->ctrl_interface_group);
        if (params->override_driver)
                global->params.override_driver =
                        os_strdup(params->override_driver);
@@ -2810,6 +3421,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                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;
 }
 
@@ -2861,12 +3480,12 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        if (global == NULL)
                return;
 
-#ifdef CONFIG_P2P
-       wpas_p2p_deinit_global(global);
-#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+       wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
 
        while (global->ifaces)
-               wpa_supplicant_remove_iface(global, global->ifaces);
+               wpa_supplicant_remove_iface(global, global->ifaces, 1);
 
        if (global->ctrl_iface)
                wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
@@ -2894,12 +3513,16 @@ void wpa_supplicant_deinit(struct wpa_global *global)
                os_free(global->params.pid_file);
        }
        os_free(global->params.ctrl_interface);
+       os_free(global->params.ctrl_interface_group);
        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();
 }
 
 
@@ -2917,6 +3540,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
                }
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+               wpas_init_ext_pw(wpa_s);
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -2984,6 +3610,22 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        int *freqs = NULL;
 
        /*
+        * Remove possible authentication timeout since the connection failed.
+        */
+       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       if (wpa_s->disconnected) {
+               /*
+                * There is no point in blacklisting the AP if this event is
+                * generated based on local request to disconnect.
+                */
+               wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
+                       "indication since interface has been put into "
+                       "disconnected state");
+               return;
+       }
+
+       /*
         * 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
@@ -3014,6 +3656,18 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
                }
        }
 
+       /*
+        * Add previous failure count in case the temporary blacklist was
+        * cleared due to no other BSSes being available.
+        */
+       count += wpa_s->extra_blacklist_count;
+
+       if (count > 3 && wpa_s->current_ssid) {
+               wpa_printf(MSG_DEBUG, "Continuous association failures - "
+                          "consider temporary network disabling");
+               wpas_auth_failed(wpa_s);
+       }
+
        switch (count) {
        case 1:
                timeout = 100;
@@ -3024,16 +3678,25 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        case 3:
                timeout = 1000;
                break;
-       default:
+       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));
+
+       wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -3042,3 +3705,280 @@ 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;
+#ifdef CONCURRENT_MODE
+       if (ssid->disabled)
+               return 1;
+#endif
+       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;
+
+       if (wpa_supplicant_fast_associate(wpa_s) != 1)
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+/**
+ * wpas_wpa_is_in_progress - Check whether a connection is in progress
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is to check if the wpa state is in beginning of the connection
+ * during 4-way handshake or group key handshake with WPA on any shared
+ * interface.
+ */
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+{
+       const char *rn, *rn2;
+       struct wpa_supplicant *ifs;
+
+       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_AUTHENTICATING &&
+                   ifs->wpa_state != WPA_COMPLETED) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
+                               "on interface %s - defer scan", ifs->ifname);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
index d393015..d73d371 100644 (file)
@@ -214,6 +214,22 @@ fast_reauth=1
 #      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
@@ -221,12 +237,83 @@ fast_reauth=1
 # 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
+
+# Enabled SAE finite cyclic groups in preference order
+# By default (if this parameter is not set), the mandatory group 19 (ECC group
+# defined over a 256-bit prime order field) is preferred, but other groups are
+# also enabled. If this parameter is set, the groups will be tried in the
+# indicated order. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=21 20 19 26 25
+
+# Default value for DTIM period (if not overridden in network block)
+#dtim_period=2
+
+# Default value for Beacon interval (if not overridden in network block)
+#beacon_int=100
+
+# Additional vendor specific elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements). This is used in AP and P2P GO modes.
+#ap_vendor_elements=dd0411223301
+
+# Ignore scan results older than request
+#
+# The driver may have a cache of scan results that makes it return
+# information that is older than our scan trigger. This parameter can
+# be used to configure such old information to be ignored instead of
+# allowing it to update the internal BSS table.
+#ignore_old_scan_res=0
+
+# scan_cur_freq: Whether to scan only the current frequency
+# 0:  Scan all available frequencies. (Default)
+# 1:  Scan current operating frequency if another VIF on the same radio
+#     is already associated.
 
 # Interworking (IEEE 802.11u)
 
@@ -239,23 +326,136 @@ fast_reauth=1
 # is enabled.
 # hessid=00:11:22:33:44:55
 
-# Home Realm for Interworking
-#home_realm=example.com
-
-# Username for Interworking network selection
-#home_username=user
-
-# Password for Interworking network selection
-#home_password=secret
-
-# CA certificate for Interworking network selection
-#home_ca_cert=/etc/cert/ca.pem
-
-# IMSI in <MCC> | <MNC> | '-' | <MSIN> format
-#home_imsi=232010000000000
+# 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
 
-# Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> format
-#home_milenage=90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123
+# 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@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
 #
@@ -274,8 +474,10 @@ fast_reauth=1
 #      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
+# 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)
@@ -326,6 +528,26 @@ fast_reauth=1
 # set, scan results that do not match any of the specified frequencies are not
 # considered when selecting a BSS.
 #
+# This can also be set on the outside of the network block. In this case,
+# it limits the frequencies that will be scanned.
+#
+# 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)
@@ -341,6 +563,16 @@ fast_reauth=1
 # 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)
@@ -366,7 +598,8 @@ fast_reauth=1
 # 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).
+# 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
@@ -389,7 +622,7 @@ fast_reauth=1
 #
 # proactive_key_caching:
 # Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
+# 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
@@ -427,7 +660,8 @@ fast_reauth=1
 #      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)
+#      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.
@@ -435,7 +669,8 @@ fast_reauth=1
 #      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.
+#      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
@@ -538,6 +773,25 @@ fast_reauth=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
@@ -561,6 +815,11 @@ fast_reauth=1
 #      interface used for EAPOL. The default value is suitable for most
 #      cases.
 #
+# ocsp: Whether to use/require OCSP to check server certificate
+#      0 = do not use OCSP stapling (TLS certificate status extension)
+#      1 = try to use OCSP stapling, but not require response
+#      2 = require valid OCSP stapling response
+#
 # 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
@@ -587,6 +846,71 @@ fast_reauth=1
 # 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
+
+# Beacon interval (default: 100 TU)
+#beacon_int=100
+
+# 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.
+
+# disable_vht: Whether VHT should be disabled.
+# 0 = VHT enabled (if AP supports it)
+# 1 = VHT disabled
+#
+# vht_capa: VHT capabilities to set in the override
+# vht_capa_mask: mask of VHT capabilities
+#
+# vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8
+# vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8
+#  0: MCS 0-7
+#  1: MCS 0-8
+#  2: MCS 0-9
+#  3: not supported
+
 # Example blocks:
 
 # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
@@ -919,3 +1243,10 @@ SGVsbG8gV29ybGQhCg==
 network={
        key_mgmt=NONE
 }
+
+
+# Example config file that will only scan on channel 36.
+freq_list=5180
+network={
+       key_mgmt=NONE
+}
diff --git a/wpa_supplicant/wpa_supplicant.nsi b/wpa_supplicant/wpa_supplicant.nsi
deleted file mode 100644 (file)
index b9f0162..0000000
+++ /dev/null
@@ -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-@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
diff --git a/wpa_supplicant/wpa_supplicant_conf.mk b/wpa_supplicant/wpa_supplicant_conf.mk
new file mode 100644 (file)
index 0000000..74986ea
--- /dev/null
@@ -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) > $@
+
+########################
diff --git a/wpa_supplicant/wpa_supplicant_conf.sh b/wpa_supplicant/wpa_supplicant_conf.sh
new file mode 100755 (executable)
index 0000000..f36eef1
--- /dev/null
@@ -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
index 5469129..659bc7b 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPA_SUPPLICANT_I_H
@@ -17,6 +11,7 @@
 
 #include "utils/list.h"
 #include "common/defs.h"
+#include "common/sae.h"
 #include "config_ssid.h"
 
 extern const char *wpa_supplicant_version;
@@ -36,6 +31,7 @@ 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
@@ -60,6 +56,14 @@ struct wpa_interface {
        const char *confname;
 
        /**
+        * confanother - Additional configuration name (file or profile) name
+        *
+        * This can also be %NULL when the additional configuration file is not
+        * used.
+        */
+       const char *confanother;
+
+       /**
         * ctrl_interface - Control interface parameter
         *
         * If a configuration file is not used, this variable can be used to
@@ -100,6 +104,15 @@ struct wpa_interface {
         * receiving of EAPOL frames from an additional interface.
         */
        const char *bridge_ifname;
+
+       /**
+        * p2p_mgmt - Interface used for P2P management (P2P Device operations)
+        *
+        * Indicates whether wpas_p2p_init() must be called for this interface.
+        * This is used only when the driver supports a dedicated P2P Device
+        * interface that is not a network interface.
+        */
+       int p2p_mgmt;
 };
 
 /**
@@ -151,6 +164,11 @@ struct wpa_params {
        char *ctrl_interface;
 
        /**
+        * ctrl_interface_group - Global ctrl_iface group
+        */
+       char *ctrl_interface_group;
+
+       /**
         * dbus_ctrl_interface - Enable the DBus control interface
         */
        int dbus_ctrl_interface;
@@ -166,6 +184,11 @@ struct wpa_params {
        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
@@ -204,6 +227,12 @@ struct p2p_srv_upnp {
        char *service;
 };
 
+struct wpa_freq_range {
+       unsigned int min;
+       unsigned int max;
+};
+
+
 /**
  * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
  *
@@ -219,20 +248,56 @@ struct wpa_global {
        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;
+       struct wpa_supplicant *p2p_invite_group;
        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_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 */
+       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;
 };
 
 /**
@@ -257,10 +322,14 @@ struct wpa_supplicant {
 #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;
+       char *confanother;
        struct wpa_config *conf;
        int countermeasures;
        os_time_t last_michael_mic_error;
@@ -285,6 +354,19 @@ struct wpa_supplicant {
        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;
+
+       enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;
+
+       /* 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)
@@ -307,6 +389,16 @@ struct wpa_supplicant {
        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 */
@@ -319,12 +411,16 @@ struct wpa_supplicant {
        int scanning;
        int sched_scanning;
        int new_connection;
+#if defined(TIZEN_EXT)
        int reassociated_connection;
+#endif /* TIZEN_EXT */
 
        int eapol_received; /* number of EAPOL packets received after the
                             * previous association event */
 
        struct scard_data *scard;
+       char imsi[20];
+       int mnc_len;
 
        unsigned char last_eapol_src[ETH_ALEN];
 
@@ -332,14 +428,58 @@ struct wpa_supplicant {
 
        struct wpa_blacklist *blacklist;
 
-       int scan_req; /* manual scan request; this forces a scan even if there
-                      * are no enabled networks in the configuration */
+       /**
+        * 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;
+       struct os_time scan_trigger_time;
        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
@@ -347,6 +487,10 @@ struct wpa_supplicant {
         */
        unsigned int probe_resp_offloads;
 
+       /* extended capabilities supported by the driver */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
+
        int max_scan_ssids;
        int max_sched_scan_ssids;
        int sched_scan_supported;
@@ -366,6 +510,7 @@ struct wpa_supplicant {
        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;
 
@@ -398,6 +543,14 @@ struct wpa_supplicant {
                                        * 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;
+#ifdef CONFIG_SAE
+               struct sae_data sae;
+               struct wpabuf *sae_token;
+               int sae_group_index;
+#endif /* CONFIG_SAE */
        } sme;
 #endif /* CONFIG_SME */
 
@@ -425,6 +578,8 @@ struct wpa_supplicant {
        unsigned int roc_waiting_drv_freq;
        int action_tx_wait_time;
 
+       int p2p_mgmt;
+
 #ifdef CONFIG_P2P
        struct p2p_go_neg_results *go_params;
        int create_p2p_iface;
@@ -455,7 +610,12 @@ struct wpa_supplicant {
        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
@@ -478,24 +638,39 @@ struct wpa_supplicant {
         */
        char cross_connect_uplink[100];
 
-       enum {
-               P2P_GROUP_REMOVAL_UNKNOWN,
-               P2P_GROUP_REMOVAL_REQUESTED,
-               P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
-               P2P_GROUP_REMOVAL_UNAVAILABLE
-       } removal_reason;
-
-       unsigned int p2p_cb_on_scan_complete:1;
+       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;
 
@@ -510,6 +685,9 @@ struct wpa_supplicant {
        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;
+       struct wpa_bss *interworking_gas_bss;
 #endif /* CONFIG_INTERWORKING */
        unsigned int drv_capa_known;
 
@@ -520,11 +698,47 @@ struct wpa_supplicant {
        } 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;
+
+#ifdef CONFIG_WNM
+       u8 wnm_dialog_token;
+       u8 wnm_reply;
+       u8 wnm_num_neighbor_report;
+       u8 wnm_mode;
+       u16 wnm_dissoc_timer;
+       u8 wnm_validity_interval;
+       u8 wnm_bss_termination_duration[12];
+       struct neighbor_report *wnm_neighbor_report_elements;
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_TESTING_GET_GTK
+       u8 last_gtk[32];
+       size_t last_gtk_len;
+#endif /* CONFIG_TESTING_GET_GTK */
 };
 
 
 /* wpa_supplicant.c */
+void wpa_supplicant_apply_ht_overrides(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+       struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_vht_overrides(
+       struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+       struct wpa_driver_associate_params *params);
+
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+                                   struct wpa_ssid *ssid);
 
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
 
@@ -543,6 +757,7 @@ 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);
@@ -550,8 +765,10 @@ 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);
+#ifdef TIZEN_EXT
 void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code);
+#endif /* TIZEN_EXT */
 
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                                   struct wpa_ssid *ssid);
@@ -565,16 +782,20 @@ 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);
+                               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);
@@ -587,11 +808,35 @@ 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);
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
+
+/**
+ * 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);
@@ -600,6 +845,10 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
                           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 wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+                                            struct wpa_ssid **selected_ssid);
 
 /* eap_register.c */
 int eap_register_methods(void);
@@ -614,4 +863,8 @@ 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 */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
new file mode 100644 (file)
index 0000000..a08eb33
--- /dev/null
@@ -0,0 +1,6 @@
+##### wpa_supplicant configuration file template #####
+update_config=1
+ctrl_interface=wlan0
+eapol_version=1
+ap_scan=1
+fast_reauth=1
index 69b0cf8..61a42bd 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -412,14 +406,6 @@ static enum wpa_states _wpa_supplicant_get_state(void *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);
@@ -451,6 +437,13 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
                /* Clear the MIC error counter when setting a new PTK. */
                wpa_s->mic_errors_seen = 0;
        }
+#ifdef CONFIG_TESTING_GET_GTK
+       if (key_idx > 0 && addr && is_broadcast_ether_addr(addr) &&
+           alg != WPA_ALG_NONE && key_len <= sizeof(wpa_s->last_gtk)) {
+               os_memcpy(wpa_s->last_gtk, key, key_len);
+               wpa_s->last_gtk_len = key_len;
+       }
+#endif /* CONFIG_TESTING_GET_GTK */
        return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
                               key, key_len);
 }
@@ -520,8 +513,6 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
 }
 #endif /* CONFIG_IEEE80211R */
 
-#endif /* CONFIG_NO_WPA */
-
 
 #ifdef CONFIG_TDLS
 
@@ -565,27 +556,46 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *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)
+       void *ctx, const u8 *peer, int add, u16 aid, u16 capability,
+       const u8 *supp_rates, size_t supp_rates_len,
+       const struct ieee80211_ht_capabilities *ht_capab,
+       const struct ieee80211_vht_capabilities *vht_capab,
+       u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct hostapd_sta_add_params params;
 
+       os_memset(&params, 0, sizeof(params));
+
        params.addr = peer;
-       params.aid = 1;
+       params.aid = aid;
        params.capability = capability;
        params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
-       params.ht_capabilities = NULL;
+
+       /*
+        * TDLS Setup frames do not contain WMM IEs, hence need to depend on
+        * qosinfo to check if the peer is WMM capable.
+        */
+       if (qosinfo)
+               params.flags |= WPA_STA_WMM;
+
+       params.ht_capabilities = ht_capab;
+       params.vht_capabilities = vht_capab;
+       params.qosinfo = qosinfo;
        params.listen_interval = 0;
        params.supp_rates = supp_rates;
        params.supp_rates_len = supp_rates_len;
        params.set = !add;
+       params.ext_capab = ext_capab;
+       params.ext_capab_len = ext_capab_len;
 
        return wpa_drv_sta_add(wpa_s, &params);
 }
 
 #endif /* CONFIG_TDLS */
 
+#endif /* CONFIG_NO_WPA */
+
 
 enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
 {
@@ -676,6 +686,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
                return;
        }
 
+       wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
+
        buflen = 100 + os_strlen(txt) + ssid->ssid_len;
        buf = os_malloc(buflen);
        if (buf == NULL)
@@ -726,6 +738,53 @@ static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
 
        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 */
 
 
@@ -746,8 +805,10 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        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;
+#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->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;
@@ -757,6 +818,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        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) {
@@ -771,6 +834,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifndef CONFIG_NO_WPA
 static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
                                             const u8 *kck,
                                             const u8 *replay_ctr)
@@ -779,6 +843,7 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
 
        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)
@@ -796,7 +861,6 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
        ctx->set_state = _wpa_supplicant_set_state;
        ctx->get_state = _wpa_supplicant_get_state;
        ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-       ctx->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;
@@ -846,7 +910,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                conf.peerkey_enabled = ssid->peerkey;
                conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
 #ifdef IEEE8021X_EAPOL
-               conf.proactive_key_caching = ssid->proactive_key_caching;
+               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 */
index 78c1b3d..9808c22 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WPAS_GLUE_H
index 870aff5..d73e023 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -17,6 +11,7 @@
 #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"
@@ -26,6 +21,7 @@
 #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"
@@ -47,6 +43,15 @@ 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 &&
@@ -70,6 +75,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                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);
@@ -77,8 +83,14 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
        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;
+               struct wpa_bss *bss;
+               struct wpa_ssid *ssid = NULL;
+               int use_fast_assoc = 0;
+
                wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
-                          "try to associate with the received credential");
+                          "try to associate with the received credential "
+                          "(freq=%u)", freq);
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                if (disabled) {
@@ -87,10 +99,29 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
                        return 1;
                }
                wpa_s->after_wps = 5;
-               wpa_s->wps_freq = wpa_s->assoc_freq;
+               wpa_s->wps_freq = freq;
                wpa_s->normal_scans = 0;
                wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+               wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+                          "without a new scan can be used");
+               bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+               if (bss) {
+                       struct wpabuf *wps;
+                       struct wps_parse_attr attr;
+
+                       wps = wpa_bss_get_vendor_ie_multi(bss,
+                                                         WPS_IE_VENDOR_TYPE);
+                       if (wps && wps_parse_msg(wps, &attr) == 0 &&
+                           attr.wps_state &&
+                           *attr.wps_state == WPS_STATE_CONFIGURED)
+                               use_fast_assoc = 1;
+                       wpabuf_free(wps);
+               }
+
+               if (!use_fast_assoc ||
+                   wpa_supplicant_fast_associate(wpa_s) != 1)
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
                return 1;
        }
 
@@ -188,6 +219,80 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *new_ssid)
+{
+       struct wpa_ssid *ssid, *next;
+
+       for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
+            ssid = next, next = ssid ? ssid->next : NULL) {
+               /*
+                * new_ssid has already been added to the list in
+                * wpas_wps_add_network(), so skip it.
+                */
+               if (ssid == new_ssid)
+                       continue;
+
+               if (ssid->bssid_set || new_ssid->bssid_set) {
+                       if (ssid->bssid_set != new_ssid->bssid_set)
+                               continue;
+                       if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
+                           0)
+                               continue;
+               }
+
+               /* compare SSID */
+               if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
+                       continue;
+
+               if (ssid->ssid && new_ssid->ssid) {
+                       if (os_memcmp(ssid->ssid, new_ssid->ssid,
+                                     ssid->ssid_len) != 0)
+                               continue;
+               } else if (ssid->ssid || new_ssid->ssid)
+                       continue;
+
+               /* compare security parameters */
+               if (ssid->auth_alg != new_ssid->auth_alg ||
+                   ssid->key_mgmt != new_ssid->key_mgmt ||
+                   ssid->proto != new_ssid->proto ||
+                   ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
+                   ssid->group_cipher != new_ssid->group_cipher)
+                       continue;
+
+               if (ssid->passphrase && new_ssid->passphrase) {
+                       if (os_strlen(ssid->passphrase) !=
+                           os_strlen(new_ssid->passphrase))
+                               continue;
+                       if (os_strcmp(ssid->passphrase, new_ssid->passphrase) !=
+                           0)
+                               continue;
+               } else if (ssid->passphrase || new_ssid->passphrase)
+                       continue;
+
+               if ((ssid->psk_set || new_ssid->psk_set) &&
+                   os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0)
+                       continue;
+
+               if (ssid->auth_alg == WPA_ALG_WEP) {
+                       if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx)
+                               continue;
+                       if (os_memcmp(ssid->wep_key, new_ssid->wep_key,
+                                     sizeof(ssid->wep_key)))
+                               continue;
+                       if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len,
+                                     sizeof(ssid->wep_key_len)))
+                               continue;
+               }
+
+               /* Remove the duplicated older network entry. */
+               wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
+               wpas_notify_network_removed(wpa_s, ssid);
+               wpa_config_remove_network(wpa_s->conf, ssid->id);
+       }
+}
+
+
 static int wpa_supplicant_wps_cred(void *ctx,
                                   const struct wps_credential *cred)
 {
@@ -248,6 +353,15 @@ static int wpa_supplicant_wps_cred(void *ctx,
                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");
@@ -265,8 +379,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
                ssid->eap.phase1 = NULL;
                os_free(ssid->eap.eap_methods);
                ssid->eap.eap_methods = NULL;
-               if (!ssid->p2p_group)
+               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");
@@ -354,16 +473,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
                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;
@@ -400,6 +509,11 @@ static int wpa_supplicant_wps_cred(void *ctx,
 
        wpas_wps_security_workaround(wpa_s, ssid, cred);
 
+       if (cred->ap_channel)
+               wpa_s->wps_ap_channel = cred->ap_channel;
+
+       wpas_wps_remove_dup_network(wpa_s, ssid);
+
 #ifndef CONFIG_NO_CONFIG_WRITE
        if (wpa_s->conf->update_config &&
            wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -408,6 +522,13 @@ static int wpa_supplicant_wps_cred(void *ctx,
        }
 #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;
 }
 
@@ -484,11 +605,61 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
 }
 
 
+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);
+       if (wpa_s->current_ssid)
+               wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
+       wpa_s->extra_blacklist_count = 0;
+
+       /*
+        * 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 */
@@ -664,6 +835,8 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
                wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
                                                        &data->set_sel_reg);
                break;
+       case WPS_EV_AP_PIN_SUCCESS:
+               break;
        }
 }
 
@@ -685,6 +858,9 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 
        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 */
@@ -711,6 +887,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
                        wpa_config_remove_network(wpa_s->conf, id);
                }
        }
+
+       wpas_wps_clear_ap_info(wpa_s);
 }
 
 
@@ -789,8 +967,8 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
-                            struct wpa_ssid *selected)
+static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *selected)
 {
        struct wpa_ssid *ssid;
 
@@ -802,6 +980,7 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
        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,
@@ -810,12 +989,35 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
                 */
                if (was_disabled != 2) {
                        ssid->disabled = ssid != selected;
-                       if (was_disabled != ssid->disabled)
+                       if (was_disabled != ssid->disabled) {
+                               if (ssid->disabled)
+                                       ssid->disabled_for_connect = 1;
                                wpas_notify_network_enabled_changed(wpa_s,
                                                                    ssid);
+                       }
                }
                ssid = ssid->next;
        }
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+                            struct wpa_ssid *selected, const u8 *bssid)
+{
+       struct wpa_bss *bss;
+
+       wpa_s->after_wps = 0;
+       wpa_s->known_wps_freq = 0;
+       if (bssid) {
+               bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+               if (bss && bss->freq > 0) {
+                       wpa_s->known_wps_freq = 1;
+                       wpa_s->wps_freq = bss->freq;
+               }
+       }
+
+       wpas_wps_temp_disable(wpa_s, selected);
+
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_s->scan_runs = 0;
@@ -848,12 +1050,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                }
        }
 #endif /* CONFIG_P2P */
-       wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+       if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+               return -1;
        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);
+       wpas_wps_reassoc(wpa_s, ssid, bssid);
        return 0;
 }
 
@@ -891,12 +1094,14 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
                            rpin, dev_pw_id);
        }
-       wpa_config_set(ssid, "phase1", val, 0);
+       if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+               return -1;
        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);
+       wpa_s->wps_ap_iter = 1;
+       wpas_wps_reassoc(wpa_s, ssid, bssid);
        return rpin;
 }
 
@@ -911,7 +1116,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
        }
 #endif /* CONFIG_AP */
 
-       if (wpa_s->wpa_state == WPA_SCANNING) {
+       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);
@@ -921,63 +1127,15 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
                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;
 }
 
 
-#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,
-                              DEV_PW_DEFAULT) < 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)
 {
@@ -1011,12 +1169,13 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
        res = os_snprintf(pos, end - pos, "\"");
        if (res < 0 || res >= end - pos)
                return -1;
-       wpa_config_set(ssid, "phase1", val, 0);
+       if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+               return -1;
        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);
+       wpas_wps_reassoc(wpa_s, ssid, bssid);
        return 0;
 }
 
@@ -1105,8 +1264,10 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
                while (first && first->next)
                        first = first->next;
                if (first && first != wpa_s) {
-                       os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid,
-                                 WPS_UUID_LEN);
+                       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 {
@@ -1122,6 +1283,23 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
 }
 
 
+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;
@@ -1160,6 +1338,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
        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) {
@@ -1206,6 +1386,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
 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;
@@ -1218,8 +1400,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
        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);
+       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;
@@ -1227,14 +1408,14 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 
 
 int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
-                           struct wpa_ssid *ssid, struct wpa_scan_res *bss)
+                           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_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+       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");
@@ -1296,19 +1477,19 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
 
 int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
                              struct wpa_ssid *ssid,
-                             struct wpa_scan_res *bss)
+                             struct wpa_bss *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);
+               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_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+               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)) {
@@ -1330,7 +1511,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
                        ret = 0;
                if (bss->beacon_ie_len) {
                        struct wpabuf *bcn_wps;
-                       bcn_wps = wpa_scan_get_vendor_ie_multi_beacon(
+                       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 "
@@ -1512,91 +1693,128 @@ 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))
+       const u8 *use_uuid = NULL;
+       u8 addr_buf[ETH_ALEN];
+
+       if (os_strcmp(uuid, "any") == 0) {
+       } else if (uuid_str2bin(uuid, u) == 0) {
+               use_uuid = u;
+       } else if (hwaddr_aton(uuid, addr_buf) == 0) {
+               use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+               if (use_uuid == NULL)
+                       return -1;
+       } else
                return -1;
        return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
-                                    any ? NULL : u,
+                                    use_uuid,
                                     (const u8 *) pin, os_strlen(pin), 300);
 }
 
 
 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
 {
-       u8 u[UUID_LEN];
+       u8 u[UUID_LEN], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
 
-       if (uuid_str2bin(uuid, u))
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
                return -1;
-       return wps_er_pbc(wpa_s->wps_er, u);
+       return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
 }
 
 
 int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
                      const char *pin)
 {
-       u8 u[UUID_LEN];
+       u8 u[UUID_LEN], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
 
-       if (uuid_str2bin(uuid, u))
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
                return -1;
-       return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+       return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
                            os_strlen(pin));
 }
 
 
-int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
-                          int id)
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+                                   struct wps_credential *cred)
 {
-       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));
+       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;
+       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) ?
+               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;
+                       cred->encr_type = WPS_ENCR_AES;
                else
-                       cred.encr_type = WPS_ENCR_TKIP;
+                       cred->encr_type = WPS_ENCR_TKIP;
                if (ssid->passphrase) {
-                       cred.key_len = os_strlen(ssid->passphrase);
-                       if (cred.key_len >= 64)
+                       cred->key_len = os_strlen(ssid->passphrase);
+                       if (cred->key_len >= 64)
                                return -1;
-                       os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+                       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);
+                       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;
+               cred->auth_type = WPS_AUTH_OPEN;
+               cred->encr_type = WPS_ENCR_NONE;
        }
-       return wps_er_set_config(wpa_s->wps_er, u, &cred);
+
+       return 0;
+}
+
+
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+                          int id)
+{
+       u8 u[UUID_LEN], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
+       struct wpa_ssid *ssid;
+       struct wps_credential cred;
+
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
+               return -1;
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (ssid == NULL || ssid->ssid == NULL)
+               return -1;
+
+       if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+               return -1;
+       return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &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];
+       u8 u[UUID_LEN], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
        struct wps_credential cred;
        size_t len;
 
-       if (uuid_str2bin(uuid, u))
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
                return -1;
        if (settings->ssid_hex == NULL || settings->auth == NULL ||
            settings->encr == NULL || settings->key_hex == NULL)
@@ -1635,11 +1853,44 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
        else
                return -1;
 
-       return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
-                            os_strlen(pin), &cred);
+       return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+                            (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], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
+
+       if (!wpa_s->wps_er)
+               return NULL;
+
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
+               return NULL;
+
+       ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+       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)
@@ -1698,6 +1949,7 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                }
        }
        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,
@@ -1709,6 +1961,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                          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);
 
@@ -1725,3 +1980,458 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                wps->dev.serial_number = wpa_s->conf->serial_number;
        }
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+                             struct wpa_ssid *ssid)
+{
+       struct wpabuf *ret;
+       struct wps_credential cred;
+
+       if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+               return NULL;
+
+       ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+       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_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                         int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+       if (id_str) {
+               int id;
+               char *end = NULL;
+               struct wpa_ssid *ssid;
+
+               id = strtol(id_str, &end, 10);
+               if (end && *end)
+                       return NULL;
+
+               ssid = wpa_config_get_network(wpa_s->conf, id);
+               if (ssid == NULL)
+                       return NULL;
+               return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+       }
+#endif /* CONFIG_WPS_ER */
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface)
+               return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+       return NULL;
+}
+
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+       if (wpa_s->conf->wps_nfc_pw_from_config) {
+               return wps_nfc_token_build(ndef,
+                                          wpa_s->conf->wps_nfc_dev_pw_id,
+                                          wpa_s->conf->wps_nfc_dh_pubkey,
+                                          wpa_s->conf->wps_nfc_dev_pw);
+       }
+
+       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) {
+               wpabuf_free(wps->dh_pubkey);
+               wps->dh_pubkey = NULL;
+               wpabuf_free(wps->dh_privkey);
+               wps->dh_privkey = 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;
+
+       /*
+        * Disable existing networks temporarily to allow the newly learned
+        * credential to be preferred. Enable the temporarily disabled networks
+        * after 10 seconds.
+        */
+       wpas_wps_temp_disable(wpa_s, NULL);
+       eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+                              NULL);
+
+       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, int cr)
+{
+       if (cr)
+               return ndef_build_wifi_hc(1);
+       return ndef_build_wifi_hr();
+}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                            int ndef, const char *uuid)
+{
+#ifdef CONFIG_WPS_ER
+       struct wpabuf *ret;
+       u8 u[UUID_LEN], *use_uuid = NULL;
+       u8 addr[ETH_ALEN], *use_addr = NULL;
+
+       if (!wpa_s->wps_er)
+               return NULL;
+
+       if (uuid == NULL)
+               return NULL;
+       if (uuid_str2bin(uuid, u) == 0)
+               use_uuid = u;
+       else if (hwaddr_aton(uuid, addr) == 0)
+               use_addr = addr;
+       else
+               return NULL;
+
+       /*
+        * Handover Select carrier record for WPS uses the same format as
+        * configuration token.
+        */
+       ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+#else /* CONFIG_WPS_ER */
+       return NULL;
+#endif /* CONFIG_WPS_ER */
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                         int ndef, int cr, const char *uuid)
+{
+       struct wpabuf *ret;
+       if (!cr)
+               return NULL;
+       ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
+       if (ret)
+               return ret;
+       return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
+}
+
+
+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;
+}
+
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *req,
+                                const struct wpabuf *sel)
+{
+       wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+       wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+       wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+       return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
+#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);
+}
index b38c091..2a212ca 100644 (file)
@@ -1,21 +1,15 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 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_res;
+struct wpa_scan_results;
 
 #ifdef CONFIG_WPS
 
@@ -40,14 +34,12 @@ 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 p2p_group, u16 dev_pw_id);
 int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
-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);
+                           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_scan_res *bss);
+                             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);
@@ -65,9 +57,30 @@ 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_config_token(struct wpa_supplicant *wpa_s,
+                                         int ndef, const char *id_str);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+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, int cr);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                         int ndef, int cr, const char *uuid);
+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);
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *req,
+                                const struct wpabuf *sel);
+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 */
 
@@ -92,14 +105,14 @@ static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
 
 static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                                          struct wpa_ssid *ssid,
-                                         struct wpa_scan_res *bss)
+                                         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_scan_res *bss)
+                                           struct wpa_bss *bss)
 {
        return 0;
 }
@@ -120,6 +133,16 @@ 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 */
diff --git a/wpadebug/AndroidManifest.xml b/wpadebug/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..9f3ca68
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="w1.fi.wpadebug"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" />
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application android:label="wpadebug">
+        <activity android:name="w1.fi.wpadebug.MainActivity"
+                  android:label="wpadebug">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+       <activity android:name="w1.fi.wpadebug.DisplayMessageActivity"
+                 android:label="Operation result"
+                 android:parentActivityName="w1.fi.wpadebug.MainActivity">
+       </activity>
+       <activity android:name="w1.fi.wpadebug.WpaNfcActivity"
+                 android:label="wpa_supplicant NFC operation"
+                 android:parentActivityName="w1.fi.wpadebug.MainActivity">
+            <intent-filter>
+               <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
+               <category android:name="android.intent.category.DEFAULT"/>
+               <data android:mimeType="application/vnd.wfa.wsc" />
+            </intent-filter>
+       </activity>
+       <activity android:name="w1.fi.wpadebug.CommandListActivity"
+                 android:label="Command list"
+                 android:parentActivityName="w1.fi.wpadebug.MainActivity">
+       </activity>
+       <activity android:name="w1.fi.wpadebug.WpaCommandListActivity"
+                 android:label="WPA command list"
+                 android:parentActivityName="w1.fi.wpadebug.MainActivity">
+       </activity>
+       <activity android:name="w1.fi.wpadebug.WpaCredActivity"
+                 android:label="Credentials"
+                 android:parentActivityName="w1.fi.wpadebug.MainActivity">
+       </activity>
+       <activity android:name="w1.fi.wpadebug.WpaCredEditActivity"
+                 android:label="Credential"
+                 android:parentActivityName="w1.fi.wpadebug.WpaCredActivity">
+       </activity>
+       <activity android:name="w1.fi.wpadebug.WpaWebViewActivity"
+                 android:label="WebView"
+                 android:launchMode="singleTop"
+                 android:noHistory="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+       </activity>
+       <receiver android:name="w1.fi.wpadebug.WifiReceiver">
+               <intent-filter>
+                       <action android:name="android.net.wifi.STATE_CHANGE" />
+                       <action android:name="android.net.wifi.RSSI_CHANGED" />
+                       <action android:name="android.net.wifi.SCAN_RESULTS" />
+                       <action android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
+                       <action android:name="android.net.wifi.supplicant.STATE_CHANGE" />
+                       <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
+               </intent-filter>
+       </receiver>
+    </application>
+</manifest>
diff --git a/wpadebug/README b/wpadebug/README
new file mode 100644 (file)
index 0000000..843b99b
--- /dev/null
@@ -0,0 +1,65 @@
+wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+Copyright (c) 2013, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+This program is licensed under the BSD license (the one with
+advertisement clause removed). See the top level README for detailed
+license text.
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+NOTE! This Android app is for debugging and testing purposes only. It is
+not supposed to be installed on a production use device and doing so may
+result in complete loss of security protections on the device.
+
+
+
+Build
+-----
+
+- Install Android SDK and build tools
+- update project target if desired; for example:
+  android list targets
+  android update project --target 1 --path $PWD
+- run: ant debug
+
+
+Installation (with adb over USB)
+------------
+
+adb install bin/wpadebug-debug.apk
+
+NOTE: Following steps enable any app on the system to get root access!
+This is not suitable for any production use. This is needed for direct
+wpa_supplicant access and some networking operating in general. You can
+still use rest of the wpadebug app without doing this, but those
+functions will not work unless this step part of installation is
+done. It should be obvious that these steps require a rooted device. In
+addition, if you do not understand what the following commands do,
+please do not run them.
+
+adb root
+adb remount
+adb shell cp /system/bin/mksh /system/bin/mksh-su
+adb shell chmod 6755 /system/bin/mksh-su
+
+Optionally, a text file with a set of command can be installed to allow
+arbitrary shell commands to be executed. This text file need to be in
+/data/local/wpadebug.cmds and use title@command format per line. For
+example:
+version@cat /proc/version
+
+Similarly, /data/local/wpadebug.wpacmds can be used to define additional
+wpa_supplicant control interface commands.
+
+
+Uninstallation
+--------------
+
+adb root
+adb remount
+adb shell rm /system/bin/mksh-su
+
+adb uninstall w1.fi.wpadebug
diff --git a/wpadebug/build.xml b/wpadebug/build.xml
new file mode 100644 (file)
index 0000000..5301e69
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="wpadebug" default="help">
+    <property file="local.properties" />
+    <property file="ant.properties" />
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+    <loadproperties srcFile="project.properties" />
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+    <import file="custom_rules.xml" optional="true" />
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+</project>
diff --git a/wpadebug/project.properties b/wpadebug/project.properties
new file mode 100644 (file)
index 0000000..7c6ac05
--- /dev/null
@@ -0,0 +1,2 @@
+# Project target.
+target=android-17
diff --git a/wpadebug/res/layout/cred_edit.xml b/wpadebug/res/layout/cred_edit.xml
new file mode 100644 (file)
index 0000000..292b30a
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <TextView
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Username"
+                   />
+               <EditText android:id="@+id/cred_edit_username"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:singleLine="true"
+                         android:lines="1"
+                         />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <TextView
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Realm"
+                   />
+               <EditText android:id="@+id/cred_edit_realm"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:singleLine="true"
+                         android:lines="1"
+                         />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <TextView
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Password"
+                   />
+               <EditText android:id="@+id/cred_edit_password"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:singleLine="true"
+                         android:lines="1"
+                         android:inputType="textPassword"
+                         />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <TextView
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Domain"
+                   />
+               <EditText android:id="@+id/cred_edit_domain"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:singleLine="true"
+                         android:lines="1"
+                         />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <TextView
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="IMSI"
+                   />
+               <EditText android:id="@+id/cred_edit_imsi"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:singleLine="true"
+                         android:lines="1"
+                         android:hint="Used only with SIM/USIM testing"
+                         />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Save"
+                   android:onClick="credSave"
+                   />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Cancel"
+                   android:onClick="credCancel"
+                   />
+       </LinearLayout>
+</LinearLayout>
diff --git a/wpadebug/res/layout/main.xml b/wpadebug/res/layout/main.xml
new file mode 100644 (file)
index 0000000..6fdd565
--- /dev/null
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+       <TextView
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:text="Framework commands"
+           />
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="WifiManager"
+                   android:onClick="wifiManagerInfo"
+                   />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="WifiInfo"
+                   android:onClick="wifiInfo"
+                   />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Networks"
+                   android:onClick="wifiConfiguredNetworks"
+                   />
+       </LinearLayout>
+       <TextView
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:text="wpa_supplicant commands"
+           />
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="wpa_supplicant commands"
+                   android:onClick="runWpaCommands"
+                   />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Credentials"
+                   android:onClick="runWpaCredentials"
+                   />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="log:info"
+                   android:onClick="wpaLogLevelInfo"
+                   />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="log:debug"
+                   android:onClick="wpaLogLevelDebug"
+                   />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="log:excessive"
+                   android:onClick="wpaLogLevelExcessive"
+                   />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <EditText android:id="@+id/edit_cmd"
+                         android:layout_weight="1"
+                         android:layout_width="0dp"
+                         android:layout_height="wrap_content"
+                         android:hint="wpa_cli command"
+                         />
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Run"
+                   android:onClick="runWpaCliCmd"
+                   />
+       </LinearLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="Shell commands"
+                   android:onClick="runCommands"
+                   />
+       </LinearLayout>
+       <TextView
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:text="NFC commands"
+           />
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:orientation="horizontal"
+                     >
+               <Button
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:text="WPS handover request"
+                   android:onClick="nfcWpsHandoverRequest"
+                   />
+       </LinearLayout>
+</LinearLayout>
diff --git a/wpadebug/res/raw/shell_commands.txt b/wpadebug/res/raw/shell_commands.txt
new file mode 100644 (file)
index 0000000..9b45d65
--- /dev/null
@@ -0,0 +1,2 @@
+id@id
+version@cat /proc/version
diff --git a/wpadebug/res/raw/wpa_commands.txt b/wpadebug/res/raw/wpa_commands.txt
new file mode 100644 (file)
index 0000000..3baa01c
--- /dev/null
@@ -0,0 +1,9 @@
+Status@STATUS
+PMKSA cache@PMKSA
+Networks@LIST_NETWORKS
+Interworking connect@INTERWORKING_SELECT auto
+Creds@LIST_CREDS
+Scan results@SCAN_RESULTS
+Flush@FLUSH
+Disconnect@DISCONNECT
+Reassociate@REASSOCIATE
diff --git a/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java b/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java
new file mode 100644 (file)
index 0000000..6d7ad4d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+
+class CmdList
+{
+    String title;
+    String command;
+
+    public CmdList(String _title, String _command)
+    {
+       title = _title;
+       command = _command;
+    }
+
+    @Override
+    public String toString()
+    {
+       return title;
+    }
+}
+
+public class CommandListActivity extends ListActivity
+{
+    private static final String TAG = "wpadebug";
+    private static final String cmdfile = "/data/local/wpadebug.cmds";
+
+    private void read_commands(ArrayList<CmdList> list, Scanner in)
+    {
+       in.useDelimiter("@");
+       while (in.hasNext()) {
+           String title = in.next();
+           String cmd = in.nextLine().substring(1);
+           list.add(new CmdList(title, cmd));
+       }
+       in.close();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+       ArrayList<CmdList> list = new ArrayList<CmdList>();
+
+       FileReader in;
+       try {
+           in = new FileReader(cmdfile);
+           read_commands(list, new Scanner(in));
+       } catch (IOException e) {
+           Toast.makeText(this, "Could not read " + cmdfile,
+                          Toast.LENGTH_SHORT).show();
+       }
+
+       InputStream inres;
+       try {
+           inres = getResources().openRawResource(R.raw.shell_commands);
+           read_commands(list, new Scanner(inres));
+       } catch (android.content.res.Resources.NotFoundException e) {
+           Toast.makeText(this, "Could not read internal resource",
+                          Toast.LENGTH_SHORT).show();
+       }
+
+       ArrayAdapter<CmdList> listAdapter;
+       listAdapter = new ArrayAdapter<CmdList>(this, android.R.layout.simple_list_item_1, list);
+
+       setListAdapter(listAdapter);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+       CmdList item = (CmdList) getListAdapter().getItem(position);
+       Toast.makeText(this, "Running: " + item.command,
+                      Toast.LENGTH_SHORT).show();
+       String message = run(item.command);
+       if (message == null)
+           return;
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       intent.putExtra(MainActivity.EXTRA_MESSAGE, message);
+       startActivity(intent);
+    }
+
+    private String run(String cmd)
+    {
+       try {
+           Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", cmd});
+           BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+           StringBuffer output = new StringBuffer();
+           int read;
+           char[] buffer = new char[1024];
+           while ((read = reader.read(buffer)) > 0)
+               output.append(buffer, 0, read);
+           reader.close();
+           proc.waitFor();
+           return output.toString();
+       } catch (IOException e) {
+           Toast.makeText(this, "Could not run command",
+                          Toast.LENGTH_LONG).show();
+           return null;
+       } catch (InterruptedException e) {
+           throw new RuntimeException(e);
+       }
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java b/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java
new file mode 100644 (file)
index 0000000..28ef85f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.MenuItem;
+import android.content.Intent;
+import android.widget.TextView;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+
+public class DisplayMessageActivity extends Activity
+{
+    private static final String TAG = "wpadebug";
+
+    String byteArrayHex(byte[] a) {
+       StringBuilder sb = new StringBuilder();
+       for (byte b: a)
+           sb.append(String.format("%02x", b));
+       return sb.toString();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+       Log.d(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+       // Get the message from the intent
+       Intent intent = getIntent();
+       String action = intent.getAction();
+       Log.d(TAG, "onCreate: action=" + action);
+
+       String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
+
+       TextView textView = new TextView(this);
+       textView.setText(message);
+       textView.setMovementMethod(new ScrollingMovementMethod());
+        setContentView(textView);
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/MainActivity.java b/wpadebug/src/w1/fi/wpadebug/MainActivity.java
new file mode 100644 (file)
index 0000000..c5d123e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.view.View;
+import android.content.Intent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.EditText;
+import android.widget.Toast;
+import android.util.Log;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiConfiguration;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+
+public class MainActivity extends Activity
+{
+    public final static String EXTRA_MESSAGE = "w1.fi.wpadebug.MESSAGE";
+    private static final String TAG = "wpadebug";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    public void runCommands(View view)
+    {
+       Intent intent = new Intent(this, CommandListActivity.class);
+       startActivity(intent);
+    }
+
+    public void runWpaCommands(View view)
+    {
+       Intent intent = new Intent(this, WpaCommandListActivity.class);
+       startActivity(intent);
+    }
+
+    public void runWpaCredentials(View view)
+    {
+       Intent intent = new Intent(this, WpaCredActivity.class);
+       startActivity(intent);
+    }
+
+    public void runWpaCliCmd(View view)
+    {
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       EditText editText = (EditText) findViewById(R.id.edit_cmd);
+       String cmd = editText.getText().toString();
+       if (cmd.trim().length() == 0) {
+           show_alert("wpa_cli command", "Invalid command");
+           return;
+       }
+       wpaCmd(view, cmd);
+    }
+
+    public void wpaLogLevelInfo(View view)
+    {
+       wpaCmd(view, "LOG_LEVEL INFO 1");
+    }
+
+    public void wpaLogLevelDebug(View view)
+    {
+       wpaCmd(view, "LOG_LEVEL DEBUG 1");
+    }
+
+    public void wpaLogLevelExcessive(View view)
+    {
+       wpaCmd(view, "LOG_LEVEL EXCESSIVE 1");
+    }
+
+    private void wpaCmd(View view, String cmd)
+    {
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       String message = run("wpa_cli " + cmd);
+       if (message == null)
+           return;
+       intent.putExtra(EXTRA_MESSAGE, message);
+       startActivity(intent);
+    }
+
+    private String run(String cmd)
+    {
+       try {
+           Log.d(TAG, "Running external process: " + cmd);
+           Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", cmd});
+           BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+           StringBuffer output = new StringBuffer();
+           int read;
+           char[] buffer = new char[1024];
+           while ((read = reader.read(buffer)) > 0)
+               output.append(buffer, 0, read);
+           reader.close();
+           proc.waitFor();
+           Log.d(TAG, "External process completed - exitValue " +
+                 proc.exitValue());
+           return output.toString();
+       } catch (IOException e) {
+           show_alert("Could not run external program",
+                      "Execution of an external program failed. " +
+                      "Maybe mksh-su was not installed.");
+           return null;
+       } catch (InterruptedException e) {
+           throw new RuntimeException(e);
+       }
+    }
+
+    private void show_alert(String title, String message)
+    {
+       AlertDialog.Builder alert = new AlertDialog.Builder(this);
+       alert.setTitle(title);
+       alert.setMessage(message);
+       alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+               public void onClick(DialogInterface dialog, int id)
+               {
+               }
+           });
+       alert.create().show();
+    }
+
+    public void wifiManagerInfo(View view)
+    {
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+       String message = "WifiState: " + manager.getWifiState() + "\n" +
+           "WifiEnabled: " + manager.isWifiEnabled() + "\n" +
+           "pingSupplicant: " + manager.pingSupplicant() + "\n" +
+           "DhcpInfo: " + manager.getDhcpInfo().toString() + "\n";
+       intent.putExtra(EXTRA_MESSAGE, message);
+       startActivity(intent);
+    }
+
+    public void wifiInfo(View view)
+    {
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+       WifiInfo wifi = manager.getConnectionInfo();
+       String message = wifi.toString() + "\n" + wifi.getSupplicantState();
+       intent.putExtra(EXTRA_MESSAGE, message);
+       startActivity(intent);
+    }
+
+    public void wifiConfiguredNetworks(View view)
+    {
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+       StringBuilder sb = new StringBuilder();
+       for (WifiConfiguration n: manager.getConfiguredNetworks())
+           sb.append(n.toString() + "\n");
+       intent.putExtra(EXTRA_MESSAGE, sb.toString());
+       startActivity(intent);
+    }
+
+    public void nfcWpsHandoverRequest(View view)
+    {
+       NfcAdapter nfc;
+       nfc = NfcAdapter.getDefaultAdapter(this);
+       if (nfc == null) {
+           Toast.makeText(this, "NFC is not available",
+                          Toast.LENGTH_LONG).show();
+           return;
+       }
+
+       NdefMessage msg;
+       msg = new NdefMessage(new NdefRecord[] {
+               NdefRecord.createMime("application/vnd.wfa.wsc",
+                                     new byte[0])
+           });
+
+       nfc.setNdefPushMessage(msg, this);
+       Toast.makeText(this, "NFC push message (WSC) configured",
+                      Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java b/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java
new file mode 100644 (file)
index 0000000..d69e05d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
+import android.os.Bundle;
+import android.util.Log;
+
+public class WifiReceiver extends BroadcastReceiver
+{
+    private static final String TAG = "wpadebug";
+
+    @Override
+    public void onReceive(Context c, Intent intent)
+    {
+       String act = intent.getAction();
+       Log.d(TAG, "Received broadcast intent: action=" + act);
+
+       Bundle bundles = intent.getExtras();
+       if (bundles == null)
+           return;
+
+       if (bundles.containsKey("bssid")) {
+           String val;
+           val = intent.getStringExtra("bssid");
+           if (val != null)
+               Log.d(TAG, "  bssid: " + val);
+       }
+
+       if (bundles.containsKey("networkInfo")) {
+           NetworkInfo info;
+           info = (NetworkInfo) intent.getParcelableExtra("networkInfo");
+           if (info != null)
+               Log.d(TAG, "  networkInfo: " + info);
+       }
+
+       if (bundles.containsKey("newRssi")) {
+           int val;
+           val = intent.getIntExtra("newRssi", -1);
+           Log.d(TAG, "  newRssi: " + val);
+       }
+
+       if (bundles.containsKey("newState")) {
+           SupplicantState state;
+           state = (SupplicantState) intent.getParcelableExtra("newState");
+           if (state != null)
+               Log.d(TAG, "  newState: " + state);
+       }
+
+       if (bundles.containsKey("previous_wifi_state")) {
+           int wifi_state;
+           wifi_state = intent.getIntExtra("previous_wifi_state", -1);
+           if (wifi_state != -1)
+               Log.d(TAG, "  previous_wifi_state: " + wifi_state);
+       }
+
+       if (bundles.containsKey("connected")) {
+           boolean connected;
+           connected = intent.getBooleanExtra("connected", false);
+           Log.d(TAG, "  connected: " + connected);
+       }
+
+       if (bundles.containsKey("supplicantError")) {
+           int error;
+           error = intent.getIntExtra("supplicantError", -1);
+           if (error != -1)
+               Log.d(TAG, "  supplicantError: " + error);
+       }
+
+       if (bundles.containsKey("wifiInfo")) {
+           WifiInfo info;
+           info = (WifiInfo) intent.getParcelableExtra("wifiInfo");
+           if (info != null)
+               Log.d(TAG, "  wifiInfo: " + info);
+       }
+
+       if (bundles.containsKey("wifi_state")) {
+           int wifi_state;
+           wifi_state = intent.getIntExtra("wifi_state", -1);
+           if (wifi_state != -1)
+               Log.d(TAG, "  wifi_state: " + wifi_state);
+       }
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java b/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java
new file mode 100644 (file)
index 0000000..e089179
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+
+public class WpaCommandListActivity extends ListActivity
+{
+    private static final String TAG = "wpadebug";
+    private static final String cmdfile = "/data/local/wpadebug.wpacmds";
+
+    private void read_commands(ArrayList<CmdList> list, Scanner in)
+    {
+       in.useDelimiter("@");
+       while (in.hasNext()) {
+           String title = in.next();
+           String cmd = in.nextLine().substring(1);
+           list.add(new CmdList(title, cmd));
+       }
+       in.close();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+       ArrayList<CmdList> list = new ArrayList<CmdList>();
+
+       FileReader in;
+       try {
+           in = new FileReader(cmdfile);
+           read_commands(list, new Scanner(in));
+       } catch (IOException e) {
+           Toast.makeText(this, "Could not read " + cmdfile,
+                          Toast.LENGTH_SHORT).show();
+       }
+
+       InputStream inres;
+       try {
+           inres = getResources().openRawResource(R.raw.wpa_commands);
+           read_commands(list, new Scanner(inres));
+       } catch (android.content.res.Resources.NotFoundException e) {
+           Toast.makeText(this, "Could not read internal resource",
+                          Toast.LENGTH_SHORT).show();
+       }
+
+       ArrayAdapter<CmdList> listAdapter;
+       listAdapter = new ArrayAdapter<CmdList>(this, android.R.layout.simple_list_item_1, list);
+
+       setListAdapter(listAdapter);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+       CmdList item = (CmdList) getListAdapter().getItem(position);
+       Toast.makeText(this, "Running: " + item.command,
+                      Toast.LENGTH_SHORT).show();
+       String message = run(item.command);
+       if (message == null)
+           return;
+       Intent intent = new Intent(this, DisplayMessageActivity.class);
+       intent.putExtra(MainActivity.EXTRA_MESSAGE, message);
+       startActivity(intent);
+    }
+
+    private String run(String cmd)
+    {
+       try {
+           Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", "wpa_cli " + cmd});
+           BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+           StringBuffer output = new StringBuffer();
+           int read;
+           char[] buffer = new char[1024];
+           while ((read = reader.read(buffer)) > 0)
+               output.append(buffer, 0, read);
+           reader.close();
+           proc.waitFor();
+           return output.toString();
+       } catch (IOException e) {
+           Toast.makeText(this, "Could not run command",
+                          Toast.LENGTH_LONG).show();
+           return null;
+       } catch (InterruptedException e) {
+           throw new RuntimeException(e);
+       }
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java b/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java
new file mode 100644 (file)
index 0000000..3902f09
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.util.ArrayList;
+import java.util.ListIterator;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import android.app.ListActivity;
+import android.app.ActionBar;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ListView;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+class Credential
+{
+    int id;
+    String realm;
+    String username;
+    String domain;
+    String imsi;
+
+    public Credential(String entry)
+    {
+       String fields[] = entry.split("\t");
+       id = Integer.parseInt(fields[0]);
+       if (fields.length > 1)
+           realm = fields[1];
+       else
+           realm = "";
+       if (fields.length > 2)
+           username = fields[2];
+       else
+           username = "";
+       if (fields.length > 3 && fields[3].length() > 0)
+           domain = fields[3];
+       else
+           domain = null;
+       if (fields.length > 4 && fields[4].length() > 0)
+           imsi = fields[4];
+       else
+           imsi = null;
+    }
+
+    public Credential(int _id, String _username, String _realm, String _domain,
+                     String _imsi)
+    {
+       id = _id;
+       username = _username;
+       realm = _realm;
+       domain = _domain;
+       imsi = _imsi;
+    }
+
+
+    @Override
+    public String toString()
+    {
+       String res = id + " - " + username + "@" + realm;
+       if (domain != null)
+           res += " (domain=" + domain + ")";
+       if (imsi != null)
+           res += " (imsi=" + imsi + ")";
+       return res;
+    }
+}
+
+public class WpaCredActivity extends ListActivity
+{
+    private static final String TAG = "wpadebug";
+    static final int CRED_EDIT_REQ = 0;
+    private ArrayList<Credential> mList;
+    private ArrayAdapter<Credential> mListAdapter;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+       mList = new ArrayList<Credential>();
+
+       String res = run("LIST_CREDS");
+       if (res == null) {
+           Toast.makeText(this, "Could not get credential list",
+                          Toast.LENGTH_LONG).show();
+           finish();
+           return;
+       }
+
+       String creds[] = res.split("\n");
+       for (String cred: creds) {
+           if (Character.isDigit(cred.charAt(0)))
+               mList.add(new Credential(cred));
+       }
+
+       mListAdapter = new ArrayAdapter<Credential>(this, android.R.layout.simple_list_item_1, mList);
+
+       setListAdapter(mListAdapter);
+       registerForContextMenu(getListView());
+
+       ActionBar abar = getActionBar();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+       menu.add(0, 0, 0, "Add credential");
+       return true;
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode,
+                                   Intent data)
+    {
+       if (requestCode == CRED_EDIT_REQ) {
+           if (resultCode != RESULT_OK)
+               return;
+
+           String username = data.getStringExtra("username");
+
+           String realm = data.getStringExtra("realm");
+
+           String domain = data.getStringExtra("domain");
+           if (domain != null && domain.length() == 0)
+               domain = null;
+
+           String imsi = data.getStringExtra("imsi");
+           if (imsi != null && imsi.length() == 0)
+               imsi = null;
+
+           String password = data.getStringExtra("password");
+           if (password != null && password.length() == 0)
+               password = null;
+
+           String res = run("ADD_CRED");
+           if (res == null || res.contains("FAIL")) {
+               Toast.makeText(this, "Failed to add credential",
+                              Toast.LENGTH_LONG).show();
+               return;
+           }
+
+           int id = -1;
+           String lines[] = res.split("\n");
+           for (String line: lines) {
+               if (Character.isDigit(line.charAt(0))) {
+                   id = Integer.parseInt(line);
+                   break;
+               }
+           }
+
+           if (id < 0) {
+               Toast.makeText(this, "Failed to add credential (invalid id)",
+                              Toast.LENGTH_LONG).show();
+               return;
+           }
+
+           if (!set_cred_quoted(id, "username", username) ||
+               !set_cred_quoted(id, "realm", realm) ||
+               (password != null &&
+                !set_cred_quoted(id, "password", password)) ||
+               (domain != null && !set_cred_quoted(id, "domain", domain)) ||
+               (imsi != null && !set_cred_quoted(id, "imsi", imsi))) {
+               run("REMOVE_CRED " + id);
+               Toast.makeText(this, "Failed to set credential field",
+                              Toast.LENGTH_LONG).show();
+               return;
+           }
+
+           mListAdapter.add(new Credential(id, username, realm, domain, imsi));
+       }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item)
+    {
+       if (item.getTitle().equals("Add credential")) {
+           startActivityForResult(new Intent(this, WpaCredEditActivity.class),
+                                  CRED_EDIT_REQ);
+           return true;
+       }
+       return false;
+    }
+
+    public void onCreateContextMenu(android.view.ContextMenu menu, View v,
+                                   android.view.ContextMenu.ContextMenuInfo menuInfo)
+    {
+       menu.add(0, v.getId(), 0, "Delete");
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item)
+    {
+       if (item.getTitle().equals("Delete")) {
+           AdapterContextMenuInfo info =
+               (AdapterContextMenuInfo) item.getMenuInfo();
+           Credential cred = (Credential) getListAdapter().getItem(info.position);
+           String res = run("REMOVE_CRED " + cred.id);
+           if (res == null || !res.contains("OK")) {
+               Toast.makeText(this, "Failed to delete credential",
+                              Toast.LENGTH_LONG).show();
+           } else
+               mListAdapter.remove(cred);
+           return true;
+       }
+       return super.onContextItemSelected(item);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+       Credential item = (Credential) getListAdapter().getItem(position);
+       Toast.makeText(this, "Credential selected: " + item,
+                      Toast.LENGTH_SHORT).show();
+    }
+
+    private String run(String cmd)
+    {
+       try {
+           Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", "wpa_cli " + cmd});
+           BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+           StringBuffer output = new StringBuffer();
+           int read;
+           char[] buffer = new char[1024];
+           while ((read = reader.read(buffer)) > 0)
+               output.append(buffer, 0, read);
+           reader.close();
+           proc.waitFor();
+           return output.toString();
+       } catch (IOException e) {
+           Toast.makeText(this, "Could not run command",
+                          Toast.LENGTH_LONG).show();
+           return null;
+       } catch (InterruptedException e) {
+           throw new RuntimeException(e);
+       }
+    }
+
+    private boolean set_cred(int id, String field, String value)
+    {
+       String res = run("SET_CRED " + id + " " + field + " " + value);
+       return res != null && res.contains("OK");
+    }
+
+    private boolean set_cred_quoted(int id, String field, String value)
+    {
+       String value2 = "'\"" + value + "\"'";
+       return set_cred(id, field, value2);
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java b/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java
new file mode 100644 (file)
index 0000000..3f846c7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+public class WpaCredEditActivity extends Activity
+{
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.cred_edit);
+    }
+
+    public void credSave(View view)
+    {
+       Intent data = new Intent();
+       EditText edit;
+
+       edit = (EditText) findViewById(R.id.cred_edit_username);
+       data.putExtra("username", edit.getText().toString());
+
+       edit = (EditText) findViewById(R.id.cred_edit_realm);
+       data.putExtra("realm", edit.getText().toString());
+
+       edit = (EditText) findViewById(R.id.cred_edit_password);
+       data.putExtra("password", edit.getText().toString());
+
+       edit = (EditText) findViewById(R.id.cred_edit_domain);
+       data.putExtra("domain", edit.getText().toString());
+
+       edit = (EditText) findViewById(R.id.cred_edit_imsi);
+       data.putExtra("imsi", edit.getText().toString());
+
+       setResult(Activity.RESULT_OK, data);
+       finish();
+    }
+
+    public void credCancel(View view)
+    {
+       setResult(Activity.RESULT_CANCELED);
+       finish();
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java b/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java
new file mode 100644 (file)
index 0000000..6a16017
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.MenuItem;
+import android.content.Intent;
+import android.content.DialogInterface;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+
+public class WpaNfcActivity extends Activity
+{
+    private static final String TAG = "wpadebug";
+
+    String byteArrayHex(byte[] a) {
+       StringBuilder sb = new StringBuilder();
+       for (byte b: a)
+           sb.append(String.format("%02x", b));
+       return sb.toString();
+    }
+
+    private void show_alert(String title, String message)
+    {
+       AlertDialog.Builder alert = new AlertDialog.Builder(this);
+       alert.setTitle(title);
+       alert.setMessage(message);
+       alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+               public void onClick(DialogInterface dialog, int id)
+               {
+                   finish();
+               }
+           });
+       alert.create().show();
+    }
+
+    private String wpaCmd(String cmd)
+    {
+       try {
+           Log.d(TAG, "Executing wpaCmd: " + cmd);
+           Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", "wpa_cli " + cmd});
+           BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+           StringBuffer output = new StringBuffer();
+           int read;
+           char[] buffer = new char[1024];
+           while ((read = reader.read(buffer)) > 0)
+               output.append(buffer, 0, read);
+           reader.close();
+           proc.waitFor();
+           Log.d(TAG, "External process completed - exitValue " +
+                 proc.exitValue());
+           return output.toString();
+       } catch (IOException e) {
+           show_alert("Could not run external program",
+                      "Execution of an external program failed. " +
+                      "Maybe mksh-su was not installed.");
+           return null;
+       } catch (InterruptedException e) {
+           throw new RuntimeException(e);
+       }
+    }
+
+    public boolean report_tag_read(byte[] payload)
+    {
+       String res = wpaCmd("WPS_NFC_TAG_READ " + byteArrayHex(payload));
+       if (res == null)
+           return false;
+       if (!res.contains("OK")) {
+           Toast.makeText(this, "Failed to report WSC tag read to " +
+                          "wpa_supplicant", Toast.LENGTH_LONG).show();
+       } else {
+           Toast.makeText(this, "Reported WSC tag read to wpa_supplicant",
+                          Toast.LENGTH_LONG).show();
+       }
+       finish();
+       return true;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+       super.onCreate(savedInstanceState);
+
+       Intent intent = getIntent();
+       String action = intent.getAction();
+       Log.d(TAG, "onCreate: action=" + action);
+
+       if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
+           Log.d(TAG, "NDEF discovered");
+           Parcelable[] raw = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
+           if (raw != null) {
+               Log.d(TAG, "NDEF message count: " + raw.length);
+               NdefMessage[] msgs = new NdefMessage[raw.length];
+               for (int i = 0; i < raw.length; i++) {
+                   msgs[i] = (NdefMessage) raw[i];
+                   NdefRecord rec = msgs[i].getRecords()[0];
+                   Log.d(TAG, "MIME type: " + rec.toMimeType());
+                   byte[] a = rec.getPayload();
+                   Log.d(TAG, "NDEF record: " + byteArrayHex(a));
+                   if (rec.getTnf() == NdefRecord.TNF_MIME_MEDIA &&
+                       rec.toMimeType().equals("application/vnd/wfa.wsc")) {
+                       Log.d(TAG, "WSC tag read");
+                   }
+
+                   if (!report_tag_read(a))
+                       return;
+               }
+           }
+       }
+
+       finish();
+    }
+}
diff --git a/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java b/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java
new file mode 100644 (file)
index 0000000..a7c54fc
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Window;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+public class WpaWebViewActivity extends Activity
+{
+    private static final String TAG = "wpadebug";
+    private static final String EXTRA_MESSAGE = "w1.fi.wpadebug.URL";
+    private WebView mWebView;
+    final Activity activity = this;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+       Log.d(TAG, "WpaWebViewActivity::onCreate");
+        super.onCreate(savedInstanceState);
+
+       Intent intent = getIntent();
+       String url = intent.getStringExtra(EXTRA_MESSAGE);
+       Log.d(TAG, "url=" + url);
+       if (url.equals("FINISH")) {
+           finish();
+           return;
+       }
+
+       mWebView = new WebView(this);
+       mWebView.getSettings().setJavaScriptEnabled(true);
+       mWebView.setWebViewClient(new WpaWebViewClient());
+
+       getWindow().requestFeature(Window.FEATURE_PROGRESS);
+
+       mWebView.setWebChromeClient(new WebChromeClient()
+           {
+               public void onProgressChanged(WebView view, int progress)
+               {
+                   Log.d(TAG, "progress=" + progress);
+                   activity.setProgress(progress * 1000);
+               }
+           });
+
+        setContentView(mWebView);
+
+       mWebView.loadUrl(url);
+    }
+
+    @Override
+    public void onResume()
+    {
+       Log.d(TAG, "WpaWebViewActivity::onResume");
+        super.onResume();
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent)
+    {
+       Log.d(TAG, "WpaWebViewActivity::onNewIntent");
+       super.onNewIntent(intent);
+       String url = intent.getStringExtra(EXTRA_MESSAGE);
+       Log.d(TAG, "url=" + url);
+       setIntent(intent);
+       if (url.equals("FINISH")) {
+           finish();
+           return;
+       }
+       mWebView.loadUrl(url);
+    }
+
+    private class WpaWebViewClient extends WebViewClient {
+       @Override
+       public boolean shouldOverrideUrlLoading(WebView view, String url)
+       {
+           Log.d(TAG, "shouldOverrideUrlLoading: url=" + url);
+           Intent intent = getIntent();
+           intent.putExtra(EXTRA_MESSAGE, url);
+
+           view.loadUrl(url);
+           return true;
+       }
+
+       @Override
+       public void onPageFinished(WebView view, String url)
+       {
+           Log.d(TAG, "onPageFinished: url=" + url);
+       }
+
+       public void onReceivedError(WebView view, int errorCode,
+                                   String description, String failingUrl)
+       {
+           Log.d(TAG, "Failed to load page: errorCode=" +
+                 errorCode + " description=" + description +
+                 " URL=" + failingUrl);
+           Toast.makeText(activity, "Failed to load page: " +
+                          description + " (URL=" + failingUrl + ")",
+                          Toast.LENGTH_LONG).show();
+       }
+
+       @Override
+       public void onReceivedSslError(WebView view, SslErrorHandler handler,
+                                      SslError error)
+       {
+           Log.d(TAG, "SSL error: " + error);
+
+           final SslErrorHandler h = handler;
+           AlertDialog.Builder alert = new AlertDialog.Builder(activity);
+           alert.setTitle("SSL error - Continue?");
+           alert.setMessage(error.toString())
+               .setCancelable(false)
+               .setPositiveButton("Yes", new DialogInterface.OnClickListener()
+                   {
+                       public void onClick(DialogInterface dialog, int id)
+                       {
+                           h.proceed();
+                       }
+                   })
+               .setNegativeButton("No", new DialogInterface.OnClickListener()
+                   {
+                       public void onClick(DialogInterface dialog, int id)
+                       {
+                           h.cancel();
+                       }
+                   });
+           alert.show();
+       }
+    }
+}
diff --git a/wpaspy/Makefile b/wpaspy/Makefile
new file mode 100644 (file)
index 0000000..bc920e0
--- /dev/null
@@ -0,0 +1,14 @@
+all: build
+
+SRC=wpaspy.c
+
+build: $(SRC) setup.py
+       python setup.py build
+
+install:
+       python setup.py install
+
+clean:
+       python setup.py clean
+       rm -f *~
+       rm -rf build
diff --git a/wpaspy/setup.py b/wpaspy/setup.py
new file mode 100644 (file)
index 0000000..4dbf765
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+#
+# Python bindings for wpa_ctrl (wpa_supplicant/hostapd control interface)
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+from distutils.core import setup, Extension
+
+ext = Extension(name = 'wpaspy',
+                sources = ['../src/common/wpa_ctrl.c',
+                           '../src/utils/os_unix.c',
+                           'wpaspy.c'],
+                extra_compile_args = ["-I../src/common",
+                                      "-I../src/utils",
+                                      "-DCONFIG_CTRL_IFACE",
+                                      "-DCONFIG_CTRL_IFACE_UNIX"])
+
+setup(name = 'wpaspy',
+      ext_modules = [ext],
+      description = 'Python bindings for wpa_ctrl (wpa_supplicant/hostapd)')
diff --git a/wpaspy/test.py b/wpaspy/test.py
new file mode 100755 (executable)
index 0000000..493af7a
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+#
+# Test script for wpaspy
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import time
+import wpaspy
+
+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 = wpaspy.Ctrl(ctrl)
+            return wpas
+        except Exception, e:
+            pass
+    return None
+
+
+def main():
+    print "Testing wpa_supplicant control interface connection"
+    wpas = wpas_connect()
+    if wpas is None:
+        return
+    print "Connected to wpa_supplicant"
+    print wpas.request('PING')
+
+    mon = wpas_connect()
+    if mon is None:
+        print "Could not open event monitor connection"
+        return
+
+    mon.attach()
+    print "Scan"
+    print wpas.request('SCAN')
+
+    count = 0
+    while count < 10:
+        count += 1
+        time.sleep(1)
+        while mon.pending():
+            ev = mon.recv()
+            print ev
+            if 'CTRL-EVENT-SCAN-RESULTS' in ev:
+                print 'Scan completed'
+                print wpas.request('SCAN_RESULTS')
+                count = 10
+                pass
+
+
+if __name__ == "__main__":
+    main()
diff --git a/wpaspy/wpaspy.c b/wpaspy/wpaspy.c
new file mode 100644 (file)
index 0000000..278089b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Python bindings for wpa_ctrl (wpa_supplicant/hostapd control interface)
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "wpa_ctrl.h"
+
+
+struct wpaspy_obj {
+       PyObject_HEAD
+       struct wpa_ctrl *ctrl;
+       int attached;
+};
+
+static PyObject *wpaspy_error;
+
+
+static int wpaspy_open(struct wpaspy_obj *self, PyObject *args)
+{
+       const char *path;
+
+       if (!PyArg_ParseTuple(args, "s", &path))
+               return -1;
+       self->ctrl = wpa_ctrl_open(path);
+       if (self->ctrl == NULL)
+               return -1;
+       self->attached = 0;
+       return 0;
+}
+
+
+static void wpaspy_close(struct wpaspy_obj *self)
+{
+       if (self->ctrl) {
+               if (self->attached)
+                       wpa_ctrl_detach(self->ctrl);
+               wpa_ctrl_close(self->ctrl);
+               self->ctrl = NULL;
+       }
+
+       if (self->ob_type)
+               self->ob_type->tp_free((PyObject *) self);
+}
+
+
+static PyObject * wpaspy_request(struct wpaspy_obj *self, PyObject *args)
+{
+       const char *cmd;
+       char buf[4096];
+       size_t buflen;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "s", &cmd))
+               return NULL;
+
+       buflen = sizeof(buf) - 1;
+       ret = wpa_ctrl_request(self->ctrl, cmd, strlen(cmd), buf, &buflen,
+                              NULL);
+       if (ret == -2) {
+               PyErr_SetString(wpaspy_error, "Request timed out");
+               return NULL;
+       }
+       if (ret) {
+               PyErr_SetString(wpaspy_error, "Request failed");
+               return NULL;
+       }
+
+       buf[buflen] = '\0';
+       return Py_BuildValue("s", buf);
+}
+
+
+static PyObject * wpaspy_attach(struct wpaspy_obj *self)
+{
+       int ret;
+
+       if (self->attached)
+               Py_RETURN_NONE;
+
+       ret = wpa_ctrl_attach(self->ctrl);
+       if (ret) {
+               PyErr_SetString(wpaspy_error, "Attach failed");
+               return NULL;
+       }
+       Py_RETURN_NONE;
+}
+
+
+static PyObject * wpaspy_detach(struct wpaspy_obj *self)
+{
+       int ret;
+
+       if (!self->attached)
+               Py_RETURN_NONE;
+
+       ret = wpa_ctrl_detach(self->ctrl);
+       if (ret) {
+               PyErr_SetString(wpaspy_error, "Detach failed");
+               return NULL;
+       }
+       Py_RETURN_NONE;
+}
+
+
+static PyObject * wpaspy_pending(struct wpaspy_obj *self)
+{
+       switch (wpa_ctrl_pending(self->ctrl)) {
+       case 1:
+               Py_RETURN_TRUE;
+       case 0:
+               Py_RETURN_FALSE;
+       default:
+               PyErr_SetString(wpaspy_error, "wpa_ctrl_pending failed");
+               break;
+       }
+
+       return NULL;
+}
+
+
+static PyObject * wpaspy_recv(struct wpaspy_obj *self)
+{
+       int ret;
+       char buf[4096];
+       size_t buflen;
+
+       buflen = sizeof(buf) - 1;
+       Py_BEGIN_ALLOW_THREADS
+       ret = wpa_ctrl_recv(self->ctrl, buf, &buflen);
+       Py_END_ALLOW_THREADS
+
+       if (ret) {
+               PyErr_SetString(wpaspy_error, "wpa_ctrl_recv failed");
+               return NULL;
+       }
+
+       buf[buflen] = '\0';
+       return Py_BuildValue("s", buf);
+}
+
+
+static PyMethodDef wpaspy_methods[] = {
+       {
+               "request", (PyCFunction) wpaspy_request, METH_VARARGS,
+               "Send a control interface command and return response"
+       },
+       {
+               "attach", (PyCFunction) wpaspy_attach, METH_NOARGS,
+               "Attach as an event monitor"
+       },
+       {
+               "detach", (PyCFunction) wpaspy_detach, METH_NOARGS,
+               "Detach an event monitor"
+       },
+       {
+               "pending", (PyCFunction) wpaspy_pending, METH_NOARGS,
+               "Check whether any events are pending"
+       },
+       {
+               "recv", (PyCFunction) wpaspy_recv, METH_NOARGS,
+               "Received pending event"
+       },
+       { NULL, NULL, 0, NULL }
+};
+
+static PyMemberDef wpaspy_members[] = {
+       {
+               "attached", T_INT, offsetof(struct wpaspy_obj, attached),
+               READONLY,
+               "Whether instance is attached as event monitor"
+       },
+       { NULL }
+};
+
+static PyTypeObject wpaspy_ctrl = {
+       PyObject_HEAD_INIT(NULL)
+       .tp_name = "wpaspy.Ctrl",
+       .tp_basicsize = sizeof(struct wpaspy_obj),
+       .tp_getattro = PyObject_GenericGetAttr,
+       .tp_setattro = PyObject_GenericSetAttr,
+       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .tp_methods = wpaspy_methods,
+       .tp_members = wpaspy_members,
+       .tp_init = (initproc) wpaspy_open,
+       .tp_dealloc = (destructor) wpaspy_close,
+       .tp_new = PyType_GenericNew,
+};
+
+
+static PyMethodDef module_methods[] = {
+       { NULL, NULL, 0, NULL }
+};
+
+
+PyMODINIT_FUNC initwpaspy(void)
+{
+       PyObject *mod;
+
+       PyType_Ready(&wpaspy_ctrl);
+       mod = Py_InitModule("wpaspy", module_methods);
+       wpaspy_error = PyErr_NewException("wpaspy.error", NULL, NULL);
+
+       Py_INCREF(&wpaspy_ctrl);
+       Py_INCREF(wpaspy_error);
+
+       PyModule_AddObject(mod, "Ctrl", (PyObject *) &wpaspy_ctrl);
+       PyModule_AddObject(mod, "error", wpaspy_error);
+}
diff --git a/wpaspy/wpaspy.py b/wpaspy/wpaspy.py
new file mode 100644 (file)
index 0000000..678695f
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+#
+# wpa_supplicant/hostapd control interface using Python
+# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import socket
+import select
+
+counter = 0
+
+class Ctrl:
+    def __init__(self, path):
+        global counter
+        self.started = False
+        self.attached = False
+        self.s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+        self.dest = path
+        self.local = "/tmp/wpa_ctrl_" + str(os.getpid()) + '-' + str(counter)
+        counter += 1
+        self.s.bind(self.local)
+        self.s.connect(self.dest)
+        self.started = True
+
+    def __del__(self):
+        self.close()
+
+    def close(self):
+        if self.attached:
+            self.detach()
+        if self.started:
+            self.s.close()
+            os.unlink(self.local)
+            self.started = False
+
+    def request(self, cmd):
+        self.s.send(cmd)
+        [r, w, e] = select.select([self.s], [], [], 10)
+        if r:
+            return self.s.recv(4096)
+        raise Exception("Timeout on waiting response")
+
+    def attach(self):
+        if self.attached:
+            return None
+        res = self.request("ATTACH")
+        if "OK" in res:
+            return None
+        raise Exception("ATTACH failed")
+
+    def detach(self):
+        if not self.attached:
+            return None
+        res = self.request("DETACH")
+        if "OK" in res:
+            return None
+        raise Exception("DETACH failed")
+
+    def pending(self):
+        [r, w, e] = select.select([self.s], [], [], 0)
+        if r:
+            return True
+        return False
+
+    def recv(self):
+        res = self.s.recv(4096)
+        return res